将 SWI-Prolog 连接到 C++ 的问题

Posted

技术标签:

【中文标题】将 SWI-Prolog 连接到 C++ 的问题【英文标题】:Problems interfacing SWI-Prolog to C++ 【发布时间】:2014-07-07 02:45:00 【问题描述】:

我想尽办法让 SWI-Prolog 与 C++ 配合得很好。现在,在我开始确切地解释我的问题是什么之前,我想先说明我的项目是关于什么的,以及我选择了哪些工具来开发解决方案。

我的教授分配给我的任务是开发一个 GUI 程序作为 SWI-prolog 的前端,而这个前端是用 C++ 开发的。我选择使用 Qt 来设计 GUI,并使用 C++ 作为后端将 SWI-Prolog 连接到应用程序。这个应用程序的用户应该能够输入一些列表,然后通过 prolog 选择要应用于它们的操作,例如,如果我输入了一个数字列表,然后通过单击一个按钮,用户可以获得另一个列表此列表中成对的数字(如果有的话)。我正在基于 archlinux 和 manjaro 开发一个 unix 操作系统,更具体地说,是 netrunner 滚动发行版。

我做了一些研究,似乎为了连接 SWI-Prolog 最好的做法是使用 Volker Wysk 开发的头文件和源文件;供参考,这里是包含这些文件的压缩文件的链接http://www.volker-wysk.de/swiprolog-c++/index.html

现在这是我的问题:如果您访问了我刚刚给您的页面,您会发现 SWI-Prolog 接口的这个 C++ 实现已经很老了:上次使用它是在 2002 年。我不得不修改头文件,这样我就可以摆脱一些错误,比如使用命名空间std或将#include ostream.h更改为#include ostream,所以我设法将错误计数变为只有两个我不能设法修复,我认为我无法修复,因为有两个函数的实现我在任何地方都找不到:该函数已声明,但找不到调用它们时应该运行的代码.

我现在将列出我认为最相关的文件的内容。我安装了最新版本的 SWI-Prolog,因此 SWI-Prolog.h 标头是安装最新 prolog(版本 6.6.5)时附带的最新标头。

#-------------------------------------------------
#
# Project created by QtCreator 2014-07-05T12:38:45
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = prologFrontend
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp \
    ../../../../../../../../usr/local/share/swiprolog-c++/prolog.cpp

LIBS += -L/usr/lib/swipl-6.6.5/lib/x86_64-linux -lswipl

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

prologFrontend.pro 文件(Qt 创建者项目文件)的内容

#include "mainwindow.h"
#include <QApplication>
#include <prolog.hpp>


int main(int argc, char *argv[])

    try 
        Prolog_impl::prolog_init(argc, argv);

     catch(Prolog_impl::PlError &error) 

    


    QApplication prog(argc, argv);
    MainWindow w;
    w.show();

    return prog.exec();

ma​​in.cpp 文件的内容

我会复制 Volker Wysk 制作的头文件和源文件的全部内容,但是这里太长了,不适合。如果你从我已经发布的他的网站的链接下载它,你可以看看它们。接下来是我得到的错误以及在他制作的 .cpp 文件中发生的两个相应代码 sn-ps:

// part of SWI-Prolog, but not exportet by header file
// /usr/local/src/swiprolog-4.0.9/src/pl-funcs.h

//NOTE: this function is declared here but it's even not to be found in the header file
//prolog.hpp. Its implementation can't be found anywhere using the function definition
//navigation capability of Qt so, basically, its a function that does nothing.
extern "C"
unsigned long pl_atom_to_term(term_t in_atom,
                              term_t out_term,
                              term_t out_bindings);



bool Prolog_impl::atom_to_term(const char* text, Term* t, list<Term::Binding>* b)

  Term in_atom = Atom(text);
  Term out_term;
  Term out_bindings;

  if (!pl_atom_to_term(in_atom.lsi, out_term.lsi, out_bindings.lsi))
    return false;

  if (t) *t = out_term;
  if (b) *b = out_bindings;
  return true;

以及此代码引发的错误:/usr/local/share/swiprolog-c++/prolog.cpp:45: error: undefined reference to `pl_atom_to_term'

//Note that this code has the same issues as the one above: no implementation to be found
extern "C"
unsigned long pl_copy_term(term_t in, term_t out);


Term Prolog_impl::copy_term(Term t)

  term_t t2 = PL_new_term_ref();
  if (!pl_copy_term(t.lsi, t2))
    throw LogicError("copy_term(Term)", "failure calling pl_copy_term()");
  return Term(t2);

以及此代码引发的错误:/usr/local/share/swiprolog-c++/prolog.cpp:60: error: undefined reference to `pl_copy_term'

除了我必须对我已经提到的头文件进行的更改之外,我还必须在头文件中修复这行代码:

#include <SWI-Prolog.h>

到这里:

#include "/usr/lib/swipl-6.6.5/include/SWI-Prolog.h"

这是因为,否则编译器会抱怨找不到那个头文件。

我的猜测是这些函数曾经存在于较旧的 SWI-Prolog 版本中。我对如何处理这项任务没有真正的线索,我尝试阅读使用 volker 实现的其他替代方案,但好像网上几乎没有关于如何将 Prolog 与 C++ 接口的好信息。

非常感谢您抽出宝贵时间阅读我的问题。如果您有可行的解决方案,请告诉我。它不必是 SWI-Prolog,它可以是任何其他与 C++ 很好地接口的 Prolog 环境,并且使用或多或少与 SWI-Prolog 使用的语法相同的语法,尽管我认为语法已经是标准的所有环境。

【问题讨论】:

【参考方案1】:

包swipl-win 是一个工作的SWI-Prolog / Qt 接口,可在Linux、MacOS、Windows 上移植。我还有很多其他人here,但现在这些仅限于在 Linux 上运行...

我想知道为什么除了 Qt 特定的问题之外,当有一个“官方”接口here 时,您选择了一个旧的、未维护的 C++ 接口。该接口运行良好,基于异常处理和自动类型转换提供参数验证。然后很容易添加到界面中-例如,来自PREDICATE.h

typedef PlTerm T;
#define LOOP__   operator bool()  return next_solution(); 
#define query0(P) struct P : PlQuery  P() : PlQuery(#P, V()) LOOP__ ;
#define query1(P) struct P : PlQuery  P(T A) : PlQuery(#P, V(A)) LOOP__ ;
...

允许

query1(current_predicate)

void Completion::initialize(QSet<QString> &strings, bool reload) 
    Q_UNUSED(reload)
    T PRED;
    for (current_predicate cp(PRED); cp; ) 
        QString p = t2w(PRED);
        if (p[0].isLetter())
            strings.insert(p);
    
    qDebug() << "Completion::initialize loaded" << strings.count();

关于你的具体问题,可能那些功能已经过时了,你应该坚持C Api(也称为外语接口)记录在here。

【讨论】:

有些东西我不明白。如果您参考此链接 swi-prolog.org/FAQ/CppBinding.html ,它表示实际上有两个 c++ 绑定:一个包含在 swi-prolog 安装中,由 Jan Wielemaker 制作(我假设这是您所指的那个),另一个,沃尔克威斯克制作。现在,引用 Jan Wielemaker 的话,他说“在适当的时候,如果结果证明 Volkers one 工作正常并且更好,它可能会取代我的版本”。除了 SWI-Prolog.h,我需要在我的项目中包含哪些库才能使这一切正常工作?任何 .so 库? 好吧,注意:如果事实证明,Volkers one 工作正常且更好...... Jan 改进了 C++ 接口,因为我们在集成 Qt 时一起工作。 C++ 接口它是一个“仅标题”组件,您不需要任何额外的库。我将在您链接的页面上发表 wiki 评论,表明您遇到的问题。 我在that page 上发表了评论。我想知道您认为这是否合适。 我成功地编译了程序,链接了 swi-prolog 共享库,并在 Qt 中包含了使用 INCLUDEPATH 安装 SWI-Prolog 时附带的头文件的路径,所以我正在放弃沃尔克的实施。还没有写任何代码,但我相信它现在可以工作了。另一个问题:是否有任何教程可以用来学习如何将 C++ 与 prolog 一起用作逻辑服务器?意思是,我有一个包含规则和事实的 .pl 文件并从 GUI 进行咨询?另一方面,我认为您在该页面上写的评论是适当的。 我在博主上发布了micro tutorial...HTH【参考方案2】:

查看Makefileswiprolog-c++-0.1.0,看起来需要使用一个特殊的链接器,称为plld。因此,您需要使用常用的编译器仅生成目标文件,然后使用该链接器创建可执行文件。

makefile 中的plld 行如下所示:

main : main.o prolog.o test.pl
    plld -o $@ -ld $(CC) $^ -lstdc++

“配方”行扩展为:

plld -o main -ld gcc main.o prolog.o test.pl -lstdc++

【讨论】:

plld 在构建嵌入式应用程序或 SWI-Prolog 内核方面具有特殊作用,我在连接 Qt 时不使用它 - 相反,pkg-config 很有用,至少在 Swi-Prolog 有从源代码构建

以上是关于将 SWI-Prolog 连接到 C++ 的问题的主要内容,如果未能解决你的问题,请参考以下文章

无法将 Qml 信号连接到 C++ 插槽

如何将 C++ dll 连接到 C# 项目?

如何使用 OTL ODBC 驱动程序将 C++ 连接到 MySQL?

C++ 将许多标头连接到一个并使用这些标头功能

如何将 Qt 库连接到标准 C++ 项目?

将 sdl 连接到 Visual C++