【问题标题】:How to create a .dll file with gcc including swi-prolog.h?如何使用包含 swi-prolog.h 的 gcc 创建 .dll 文件?
【发布时间】:2021-03-25 12:16:35
【问题描述】:

我正在尝试在 Windows 10 上使用 gcc 创建一个 .dll 文件,但出现错误。 mylib.c 文件:

#include <windows.h>
#include "C:/Programme/swipl/include/SWI-Prolog.h"

static foreign_t
pl_say_hello(term_t to)
{ char *a;

  if ( PL_get_atom_chars(to, &a) )
  { MessageBox(NULL, a, "DLL test", MB_OK|MB_TASKMODAL);

    PL_succeed;
  }

  PL_fail;
}

install_t
install_mylib()
{ PL_register_foreign("say_hello", 1, pl_say_hello, 0);
}

我包含了 swi-prolog.h 文件,因为编译器抱怨它找不到像 here 这样的头文件。

所以编译不会产生任何问题:

> gcc -c mydll.c

但如果我想通过以下方式创建 .dll 文件:

> gcc -shared -o mydll.dll mydll.o

我收到以下错误:

C:\Users\Julian\AppData\Local\Temp\ccAblUMK.o:mylib.c:(.text+0x14): undefined reference to `PL_get_atom_chars'
C:\Users\Julian\AppData\Local\Temp\ccAblUMK.o:mylib.c:(.text+0x76): undefined reference to `PL_register_foreign'
collect2.exe: error: ld returned 1 exit status

有人知道这个问题吗?

更新:我也尝试过使用 swipl-ld,但它也不起作用。 (只是稍微更改了文件,但问题仍然存在)

【问题讨论】:

  • 嗯,编译的时候基本不会引用swipl自己的共享库。尝试使用 -shared 选项运行 swipl-ld。参见手册页here
  • 我也试过shared - 发生同样的错误。实际上在上面的截图中;-)
  • 啊,是的。我的错。 -v 会说更多吗?
  • 用Windows上的测试更新了我的答案,结果成功了。
  • @DavidTonhofer 非常感谢!一定是我没有从另一个source 正确安装的MinGW,或者我没有正确设置路径变量。祝你一切顺利!

标签: c swi-prolog


【解决方案1】:

我没有现成的答案,因为我从未尝试过这个但这个问题:

Building a shared library using gcc on Linux and MinGW on Windows

似乎触及到了问题:

我无法生成允许共享的构建设置 使用 gcc 和 MinGW 在 Linux 和 Windows 中构建的库, 分别。在 Linux 中,共享库不必解决所有问题 编译时的依赖关系;然而,这似乎是 窗户。

话虽如此,手册在Linking Foreign Modules 上说有一个特殊的链接工具

本节讨论(自动加载)的功能 library(shlib),提供管理共享库的接口。 我们描述了使用外部资源(Windows 中的 DLL)的过程 和 Unix 中的共享对象)称为mylib

首先,必须组装资源并使其兼容 SWI-序言。这方面的细节因平台而异。这 swipl-ld(1) 实用程序可用于在便携式设备中处理此问题 方式。典型的命令行是:

swipl-ld -o mylib file.{c,o,cc,C} ...

确保其中一个文件提供了全局 使用调用初始化模块的函数install_mylib()PL_register_foreign()。这是一个简单的示例文件mylib.c, 它创建了一个 Windows 消息框:...

不过,好像需要加上上面没有给出的选项-shared

swipl-ld 的手册是here

但是在构建基于独立可执行文件的上下文中给出 swipl 库和额外的 C 代码,这是不同的。

swipl-ld 确实在分发中,在bin 目录中。

请注意,您需要一个“模块存根”来将外部函数引入 swipl 运行时。像这样:

测试是否有效

在 Linux 上

只是一个简短的测试,但在 Linux 上(稍后我将不得不响应我的 Windows 机器)

在目录/home/rost/compilec:

C代码文件mylib.c

#include <SWI-Prolog.h>
#include <stdio.h>

static foreign_t
pl_say_hello(term_t to)
{ char *a;
  if ( PL_get_atom_chars(to, &a)) {
    printf("Hello, %s\n",a);
    PL_succeed;
  }
  else {
    PL_fail;
  }
}

install_t
install_mylib()
{ PL_register_foreign("say_hello", 1, pl_say_hello, 0);
}

Prolog 文件 mylib.pl 声明一个“存根模块”:

:- module(mylib, [ say_hello/1 ]).
:- use_foreign_library(foreign(mylib)).

以上创建完成后,使用 swipl-ld 通过编译 mylib.c:

$ swipl-ld -v -shared -o mylib mylib.c 

输出是:

eval `swipl --dump-runtime-variables`
         PLBASE="/usr/local/logic/swipl/lib/swipl"
         PLARCH="x86_64-linux"
         PLSOEXT="so"
         PLLIBDIR="/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux"
         PLLIB="-lswipl"
         PLTHREADS="yes"
/usr/bin/cc -c -fPIC -D_REENTRANT -D__SWI_PROLOG__ -I/usr/local/logic/swipl/lib/swipl/include -o mylib.o mylib.c
/usr/bin/cc -o mylib.so -shared -Wl,-rpath=/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux mylib.o -L/usr/local/logic/swipl/lib/swipl/lib/x86_64-linux -lswipl
rm mylib.o

cc 恰好是 gcc version 10.2.1(运行 cc -v 来查看)

现在开始 swipl 并调用提供的谓词。

在 Prolog Toplevel(即 Prolog 命令行)上,首先扩展外部库的搜索路径:

?- assertz(file_search_path(foreign,'/home/rost/compilec')).
true.

查阅“存根模块”:

?- [mylib].
true.

然后调用有问题的谓词:

?- say_hello('World').
Hello, World
true.

在 Windows 上

(更准确地说,在 Windows 10 上。使用起来很尴尬。)

获取 SWI-Prolog

我已经使用Download SWI-Prolog stable versions 提供的安装程序安装了SWI-Prolog,即SWI-Prolog 8.2.4-1 for Microsoft Windows (64 bit)

安装完成后,SWI-Prolog 文件树可以在C:\Program Files\swipl 中找到,bin 子目录确实包含了我们所有人。

获取 MinGW

现在获取 MinGW。这是 64 位 Windows,因此我们将获得 64-bit version(它取代了 32 位版本,并且也由另一个团队维护)。

可以在this page找到下载。

下载MinGW64-builds

旁注

我也尝试了Win-builds,但没有成功,win-builds 安装程序尝试下载软件包失败,因为 SHA-3 校验和不匹配。也许它太旧了?

旁注结束

点击MinGW64-builds。会将我们重定向到 Sourceforge(啊,nsotalgia!)并将安装程序转储到 Downloads 目录中。它通过了杀毒软件,ESet Antivirus 说它对这个可执行文件有很好的信心,计算 SHA-256 校验和然后用谷歌搜索它会带来很好的结果。太棒了。

所以运行安装程序。我填写了它要求的神秘设置如下:

Version 8.1.0     - Latest MingW version
Architecture      - Proposes "i686" (why), switch to "x86_64"
Threads           - "posix" or "win32"? Let's take "posix"
Exception         - "seh", why not, this seems to be the modern exception format
Build revision 0  - Ok I guess

(对于 SEH 与 SLJ 异常格式,请参阅 this question

在下载包和安装完成后,你会得到很多工具

C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin

现在我们可以构建我们的 DLL。打开“命令提示符”窗口:

> set PATH=C:\Program Files\swipl\bin;C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%

> cd (to where the mylib.c and mylib.pl files reside)

> swipl-ld -v -shared -o mylib mylib.c

我们看到了:

eval `swipl.exe --dump-runtime-variables`
     PLBASE="c:/program files/swipl"
     PLARCH="x64-win64"
     PLSOEXT="dll"
     PLLIBDIR="c:/program files/swipl/bin"
     PLLIB="-lswipl"
     PLTHREADS="yes"
 gcc.exe -c -D_REENTRANT -D__WINDOWS__ -D_WINDOWS -D__SWI_PROLOG__ -I"c:/program files/swipl/include" -o mylib.obj mylib.c
 gcc.exe -o mylib.dll -shared mylib.obj -L"c:/program files/swipl/bin" -lswipl
 rm mylib.obj

并且文件mylib.dll已成功创建。

旁注:

如果您在 Linux 上查看,file 会说这是一个PE/COFF 文件:

$ file mylib.dll
mylib.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows

nm(1) 在 DLL 上工作(太好了!)并列出了导出的过程:

$ nm mylib.dll  | grep say
000000006e5813b0 t pl_say_hello

嗯,那个 DLL 文件只是一个序列化的结构,就像其他的一样,

旁注结束

swipl 可以使用 DLL 吗?可以!

开始swipl。假设我们在目录C:\Users\francisbacon\Documents\Compiling 中有mylib.dll

1 ?-
assertz(file_search_path(foreign,'C:/Users/francisbacon/Documents/Compiling')).
true.

2 ?-
[mylib].
true.

3 ?-
say_hello('World').
Hello, World
true.

【讨论】:

  • Here 据说,我不需要那个,因为来自 GNU Binutils 的 ld 链接器似乎是自己做这个链接的。正如SWIP-Prolog 似乎肯定的那样。
  • @Johnny 据我了解,GNU ld 在 Windows 上是不够的,你必须使用 swipl-ld 来生成 DLL,因为微软的原因。你试过了吗?
  • 是的,发生了同样的错误 - 更新了我的问题^^
猜你喜欢
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 2012-03-17
  • 1970-01-01
相关资源
最近更新 更多