Subject: Re: help regarding interfacing of C with prolog

From: Nicos Angelopoulos <[email-masked]>
Date: Wed, 10 May 2000 16:45:28 +0100

On Wed, 10 May 2000, Jan Wielemaker wrote:

> On Wed, 10 May 2000, Ankit Jalote wrote:
> >Respected Sir,
> >                I need your help regarding a project.Actually I have done a
> >  project in C and now in its extension I need it to interface it with
> >  SWI-prolog.I have accessed the chapter 5 of reference manual but still it
> >  is not clear since i have just learnt prolog.Can you give some easy
> >  examples regarding the interface.I really need to do this.
> >  							thanking you,
> >  							Ankit Jalote
> 
> Sorry to say, but questions like this are of no use.  It is totally
> unclear what problem you are facing using the interface.  There are
> various examples in the manual and many more in the source-code, which
> comes with various foreign packages.  You can also look in the
> `packages' page of the home-page, providing C/C++-sources to various
> extensions.
> 
> If none of this helps, describe what you want to achieve and include
> (abstracted) code on how you want to do that, but you don't understand
> why it doesn't work.
> 
> 	Regards --- Jan
> 
> 

although there are a few minor _bugs_ in the manual 
eg in the hostname example, 

( 	PL_put_atom_chars(tmp, buf);
         return PL_unify(name, buf);

	should be 

	return PL_unify(name, tmp);

) 

(or at least i think it should ne :) ) 

since i just did some c calling from swi-pl 
i include a complete example of how to 
call C from prolog on a UNIX box 

please note that all the info/code are in the manual 
and i claim no authorship

regards

nicos.

++++

so given the two files pl_hostname.c and c_hostname.pl
(see end of message) 

the objective is to integrate them so 
we can use

?- c_hostname( X ). 

H = kea ;

No
?-

at the prolog prompt 

there two main ways to do that, 
a) you create a shared object that will know how to 
	implement c_hostname/1.

b) create a new prolog (swi) interpreter that has 
	built-in knowledge about c_hostname_1.

a) 

Step 1.

compile your c program to get a .o file 

in the system i use and for this example:

gcc -I/home/kea/nangelop/include -L/home/kea/nangelop/lib -O2 -Wall -fpic
-DHAVE_CONFIG_H -c pl_hostname.c -o c_hostname.o

where 
/home/nangelop/include  is the location for  SWI-Prolog.h

and 
/home/nangelop/lib    is the location for libreadline.a

Step 2.

link your .o file to get a shared library

eg

gcc -shared -L/home/nangelop/lib -o pl_hostname.so pl_hostname.o

(in both steps you can normally do without the -l<libpath> flag)

Step 3.

put the shared object somewhere that can be found by pl at runtime 

i) 
the cosiest place is PLBASE/lib/<arch>/ 

ii) 
alternative set your LD_LIBRARY_PATH
with something like 
setenv LD_LIBRARY_PATH <PATH_TO_pl_hostname> 

iii) 
if you are an admin you should know where to put it :) 

Step 4

start swi prolog, consult c_hostname.pl and use the predicate defined

eg

% pl 

Welcome to SWI-Prolog (Version 3.3.6)
Copyright (c) 1990-2000 University of Amsterdam. 
Copy policy: GPL-2 (see www.gnu.org)

For help, use ?- help(Topic). or ?- apropos(Word).

?- [c_hostname].
% c_hostname compiled 0.02 sec, 9,832 bytes

Yes
?- c_hostname( P ).

P = kea ;

No
?- 

b) 

to create a pl that knows about  c_hostname/1

simply do, 

plld -o plh pl_hostname.c 

(i get some warning here because of differences in readline and ncurses,
 but it seems safe to ignore them)

% ./plh

Welcome to SWI-Prolog (Version 3.3.6)
Copyright (c) 1990-2000 University of Amsterdam. 
Copy policy: GPL-2 (see www.gnu.org)

For help, use ?- help(Topic). or ?- apropos(Word).

?- c_hostname( H ).

H = kea ;

No
?- 

++++    c_hostname.pl

:- load_foreign_library(user:foreign(pl_hostname), hostname_install ).

+++    pl_hostname.c

#include <stdio.h>
#include <SWI-Prolog.h>
#include <unistd.h>       /* Needed for retrieving hostname */

#define READLINE 1			/* use readline interface */

#define HOSTNAMELEN	128

foreign_t
pl_hostname(term_t name)
{ char buf[HOSTNAMELEN];
        
    if ( gethostname(buf, sizeof(buf)) )
    { PL_fail; } else {
        term_t tmp = PL_new_term_ref();

          PL_put_atom_chars(tmp, buf);
          return PL_unify(name, tmp);
        }

		/* OR 
			if ( gethostname(buf, sizeof(buf)) ) {
				{PL_fail;} else {
				return PL_unify_atom_chars(name, buf);
			}
			*/
      }

static const PL_extension hostname_predicates[] =
{
/*{ "name",	arity,  function,	PL_FA_<flags> },*/
  {"c_hostname", 1, pl_hostname, 0},
  { NULL,	0, 	NULL,		0 }	/* terminating line */
};

void
hostname_install()
{	
	PL_register_extensions(hostname_predicates);
}

static void
install_hostname(int argc, char **argv)
{	
	hostname_install();
}

#ifdef READLINE
static void
install_readline(int argc, char**argv)
{ PL_install_readline();
}
#endif

int
main(int argc, char **argv)
{

#ifdef READLINE
  PL_initialise_hook(install_readline);
#endif
	PL_initialise_hook(install_hostname);
  /* PL_register_extensions(predicates);	This is the only PL_ call allowed */
					/* before PL_initialise().  It */
					/* ensures the foreign predicates */
					/* are available before loading */
					/* Prolog code */

  if ( !PL_initialise(argc, argv) )
    PL_halt(1);

  PL_halt(PL_toplevel() ? 0 : 1);

  return 0;
}