Greg
Greg

Reputation: 413

Problems interfacing SWI-Prolog to C++

i am at wit's end trying to make SWI-Prolog play nice with C++. Now, before i start explaining exactly what my problem is, i want to first state what my project is about and what tools i chose in order to develop a solution.

My professor assigned to me the task of developing a GUI program that serves as a frontend to SWI-prolog, and this frontend is to be developed in C++. I chose to use Qt to design the GUI and use C++ as a backend to bridge SWI-Prolog to the application. The user of this application should be able to input some lists and then choose operations to be applied to them through prolog, like if, for example, I input a list of numbers, then by click of a button the user gets another list of all the numbers that are pairs in this list (if there are any). I am developing on a unix OS, more specifically, netrunner rolling release, based on archlinux and manjaro.

I did some research, and it seemed that the best course of action in order to interface SWI-Prolog (may i also mention that my professor also recommended this), is to use the header and source file developed by Volker Wysk; for reference, here is the link to the compressed file that contains these files http://www.volker-wysk.de/swiprolog-c++/index.html

Now here is my problem: if you visited the page i just gave you you will see that this C++ implementation of the SWI-Prolog interface is quite old: last time it was worked on was in the year 2002. I had to modify the header file so that i could get rid of some of the errors, like putting using namespace std or changing #include ostream.h to #include ostream, and so i managed to get the error count to only two which i can't manage to fix and which i think i won't be able to because there are two functions whose implementation i can't find anywhere: the function is declared but the code that it is supposed to run when they are called can't be found.

I will now list the contents of the files i consider to be most relevant. I have the latest version of SWI-Prolog installed, and so the SWI-Prolog.h header is the latest one that comes with the installation of the newest prolog (version 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

contents of the prologFrontend.pro file (Qt creator project file)

#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();
}

contents of the main.cpp file

I would copy the whole contents of the header and source files made by Volker Wysk, but it's too long to fit in here. You can take a look at them if you download it from the link to his site i already posted. Next are the errors i am getting and the two corresponding code snippets where they happen in the .cpp file that he made:

// 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;
}

And the error that this code throws: /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);
}

and the error that this code throws: /usr/local/share/swiprolog-c++/prolog.cpp:60: error: undefined reference to `pl_copy_term'.

Aside from the changes I had to make to the header file I already mentioned, I had to fix this line of code in the header file:

#include <SWI-Prolog.h>

to this:

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

This is because, otherwise, the compiler complains that it can't find that header file.

My guess is that these functions used to exist in an older SWI-Prolog version. I have no real clue about what to do with this task, i tried reading up on other alternatives to using volker's implementation but it's like there is close to none good information on the net about how to interface Prolog with C++.

Thank you so very much for taking your time to read my question. If you have a solution that works, please let me know. It doesn't have to be SWI-Prolog, it could be any other Prolog environment that interfaces nicely with C++ and that uses more or less about the same syntax that SWI-Prolog uses, though i think that the syntax is already standard for all environments.

Upvotes: 3

Views: 2344

Answers (2)

CapelliC
CapelliC

Reputation: 60004

Package swipl-win is a working SWI-Prolog / Qt interface, portable on Linux,MacOS,Windows. I have many others here, but these are restricted to running on Linux by now...

I wonder why, apart Qt specific problems, have you chosen an old, unmaintained C++ interface, when there is an 'official' one here. This interface is working pretty well, giving parameter validation based on exception handling and automatic type conversion. Then it's easy to add to the interface - for instance, from 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__ };
...

allows

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();
}

About your specific problems, probably those functions are obsolete, you should stick to C Api (also know as foreign language interface) documented here.

Upvotes: 1

ooga
ooga

Reputation: 15501

Looking into the Makefile for swiprolog-c++-0.1.0, it looks like a special linker needs to be used, called plld. So you need to use your usual compiler to generate only the object files, then use that linker to create the executable.

The plld line in the makefile looks like this:

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

The "recipe" line expands to this:

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

Upvotes: 1

Related Questions