Usage example

In this example we create two packages using the autotools:

Example server program and client library

The procedure to export (input for the code generator - libt2n-codegen): t2nexample.cpp:
First the procedure to export is defined. It is marked for export with the attribute macro "LIBT2N_EXPORT". In this example the procedure throws an exception if the input string is "throw". The exception is passed back to the client transparently. Otherwise some text is appended and returned.
// include automatically generated code
#include "t2nexample_common.hxx"

LIBT2N_EXPORT std::string testfunc(std::string str) 
{
    // exceptions derived from libt2n::t2n_exception are passed to the client transparently
    if (str=="throw")
        throw libt2n::t2n_runtime_error("throw me around");
    return str+", testfunc() was here";
}
Required includes go into the group header file: t2nexample.hxx:
All includes required to get the declarations of the types used by the procedures to export go into the group header file. libt2n uses boost for serialization. This means all types involved in a remote procedure call must be boost serializable. In this example we only use std::string provided by <string> and boost already provides serialization for std::string in the boost/serialization/string.hpp header file.
#include <string>
#include <boost/serialization/string.hpp>
The server program: server.cpp:
We have to provide the main entry point for the server program. In this example we use a local socket and the server program simply waits until a request is received which then is handled by the generated code directly. We use a libt2n::group_command_server to handle the requests. Each libt2n::group_command_server is tied to one command group. Which source file exports it's functions into which command group is defined in the Makefile (see below).
#include <socket_server.hxx>
#include <command_server.hxx> // for group_command_server

// the automatically generated server side code (cmd_group_t2nexample class)
#include "t2nexample_server.hxx"

int main(int argc, char** argv) {
  // create local socket server (a.k.a "unix domain socket")
  // if you want to to create a tcp/ip server you pass the port to the constructor (for details take a look at the socket_server class documentation)
  libt2n::socket_server ss("./socket");
  libt2n::group_command_server<cmd_group_t2nexample> cs(ss);

  // handle requests
  while(true)
    cs.handle();

  return 0;
}
Using autoconf and automake to build a example server program and a client library.
In the configure.in(.ac) we check for libt2n using the LIBT2N_CHECK m4 macro provided by libt2n.
AC_INIT(configure.in)
AM_INIT_AUTOMAKE(libt2n-example1, 0.1)
AC_LANG_CPLUSPLUS
AC_PROG_CXX
AM_PROG_LIBTOOL

dnl check for libt2n (library and code generator)
LIBT2N_CHECK(libt2n = 0.3)

AC_OUTPUT(Makefile)
Writing the Makefile.am isn't difficult either. We have to list the command groups used. For each command group we have to list the C++ source files with the procedures to export. For each group we build a client library by listing the generated client code (group_client.cpp) in a corresponding libtool library target. The .pc file for the library is generated automatically. The sources of the server program must include the generated server code (group_server.cpp), the file with the main entry point and of course the procedure definition.
# not a GNU package. You can remove this line, if you have all needed files, that a GNU package needs
AUTOMAKE_OPTIONS = foreign

# our dependencies
INCLUDES = @LIBT2N_CFLAGS@
LDADD = @LIBT2N_LIBS@

# list your command groups (seperated by spaces)
CMDGROUPS = t2nexample

# for each command group list the files to parse for LIBT2N_EXPORT
t2nexample_GROUP = t2nexample.cpp

# unfortunately we can't set those from variables (because they are parsed by automake)

# for each group build a client library from generated source file(s)
# (if you have automake >= 1.5 you might wish to use nodist_ here)
# Note: the library name must match the group name
libt2nexample_la_SOURCES = t2nexample_client.cpp
lib_LTLIBRARIES = libt2nexample.la

# build server program
bin_PROGRAMS = libt2n-example1-server

# (if you have automake >= 1.5 you might wish to use nodist_ here)
# nodist_server_SOURCES = t2nexample_server.cpp

libt2n_example1_server_SOURCES = \
	server.cpp $(t2nexample_GROUP) \
	t2nexample_server.cpp

# include Makefile snippet doing all the magic
include codegen.make
Build and install the package
To build and install the package we first have to create the configure script and the other help scripts of the autotools by running autoreconf.
 autoreconf -f -i && ./configure && make install
 

Client using the library

Using the library is as simple as using any other library using pkg-config (the pkg-config .pc file is created automatically by the included Makefile snippet)
We only have to check that the library is installed
AC_INIT(configure.in)
AM_INIT_AUTOMAKE(libt2n-example1-client, 0.1)
AC_LANG_CPLUSPLUS
AC_PROG_CXX
AM_PROG_LIBTOOL

dnl check for the client library
PKG_CHECK_MODULES(T2NEXAMPLE, t2nexample = 0.1)

AC_OUTPUT(Makefile)
The Makefile.am needs nothing special
# not a GNU package. You can remove this line, if you have all needed files, that a GNU package needs
AUTOMAKE_OPTIONS = foreign
INCLUDES = @T2NEXAMPLE_CFLAGS@
LDADD = @T2NEXAMPLE_LIBS@
bin_PROGRAMS = libt2n-example1-client
libt2n_example1_client_SOURCES = client.cpp
The client program: client.cpp:
The example client first connects to the local socket. The connection is passed to the constructor of the generated class. To call the remote procedure the "testfunc" method is called. The example first passes "throw" to the remote procedure which will result in a exception to be thrown which is passed back to the client and thrown on the client side again. In the example the exception is caught and it is checked whether the string returned by what() is correct. If so a second remote procedure call is made and its return value is checked. Only if both tests succeed the program will exit with a status value indicating success.
// for socket_client_connection
#include <socket_client.hxx>

// include generated library header
#include "t2nexample_client.hxx"

int main(int argc, char** argv)
{
  // use a local socket (a.k.a "unix domain socket")
  // if you want to connect to a tcp/ip server you pass the port and server name to the constructor
  libt2n::socket_client_connection sc("./socket");
  // this generated class has a method for each of our exported procedures
  cmd_group_t2nexample_client cc(sc);

  bool throwok=false;

  // exceptions are passed back to the client transparently
  try
  {
    // call the remote procedure (we pass "throw" to cause a exception to be thrown)
    cc.testfunc("throw");
  }catch(libt2n::t2n_runtime_error &e){
    throwok=(std::string(e.what())=="throw me around");
  }

  // call remote procedure and check the return value is correct
  return ( throwok && ( cc.testfunc("hello") == "hello, testfunc() was here" ) )
    ? EXIT_SUCCESS : EXIT_FAILURE;
}
Build and install the package
 autoreconf -f -i && ./configure && make install
 
Test
To test whether it works we first start the server that creates a socket 'socket' in the current working directory. Then we run the client and print "ok" if it exited with a status value indicating success.
$ cd /tmp
$ file socket
socket: cannot open `socket' (No such file or directory)
$ libt2n-example1-server &
[1] 7711
$ file socket
socket: socket
$ libt2n-example1-client && echo ok
ok
$ kill %1
$ rm socket
 

Generated on Tue May 8 17:53:16 2007 for libt2n by  doxygen 1.4.7-4