Compiling a C++ D-Bus program
Read the guide to installing the C++ D-Bus bindings if you don't have the library installed already.
Since both D-Bus and C++ use statically typed systems, C++ needs to have the D-Bus interface descriptions of the objects it will use available at compile time. The dbusxx-introspect program introspects D-Bus objects and produces D-Bus XML interface descriptions. To introspect the object / in the service org.apertium.mode, one issues the command:
dbusxx-introspect / org.apertium.mode
This outputs the XML description stdout. Append > org.apertium.mode.xml to the above command to write the data to the file org.apertium.mode.xml. The contents out the created XML file should look something like:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/">
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg direction="out" type="s" />
</method>
</interface>
<interface name="org.apertium.Translate">
<method name="translate">
<arg direction="in" type="s" name="pair" />
<arg direction="in" type="a{ss}" name="options" />
<arg direction="in" type="s" name="text" />
<arg direction="out" type="s" />
</method>
</interface>
<node name="af_en"/>
<node name="en_af"/>
<node name="es_fr"/>
<node name="fr_es"/>
</node>
Now one can use the tool dbusxx-xml2cpp to generate a C++ proxy class for the D-Bus object. We will create a file called Translation-glue.h from our generated XML file by issuing:
dbusxx-xml2cpp org.apertium.mode.xml --proxy=Translation-glue.h
(Note that dbusxx-xml2cpp can also generate adaptor objects with the flag --adaptor. This is meant for creating D-Bus services with C++, which is outside of the scope of this guide.)
The generated file should look something like this:
/*
* This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!
*/
#ifndef __dbusxx__Translate_h__PROXY_MARSHAL_H
#define __dbusxx__Translate_h__PROXY_MARSHAL_H
#include <dbus-c++/dbus.h>
namespace org {
namespace apertium {
class Translate
: public ::DBus::InterfaceProxy
{
public:
Translate()
: ::DBus::InterfaceProxy("org.apertium.Translate")
{
}
public:
/* methods exported by this interface,
* this functions will invoke the corresponding methods on the remote objects
*/
::DBus::String translate( const ::DBus::String& pair,
const std::map< ::DBus::String, ::DBus::String >& options,
const ::DBus::String& text )
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << pair;
wi << options;
wi << text;
call.member("translate");
::DBus::Message ret = invoke_method(call);
::DBus::MessageIter ri = ret.reader();
::DBus::String argout;
ri >> argout;
return argout;
}
public:
/* signal handlers for this interface
*/
private:
/* unmarshalers (to unpack the DBus message before calling the actual signal handler)
*/
};
} }
#endif//__dbusxx__Translate_h__PROXY_MARSHAL_H
The next step is to create our minimal C++ program. Create a file called dbus_test.cpp with the following contents:
#include <map>
#include <iostream>
#include <sstream>
#include <string>
#include <dbus-c++/dbus.h>
#include "Translate-glue.h"
static const char* TRANSLATE_SERVICE_NAME = "org.apertium.mode";
static const char* TRANSLATE_OBJECT_PATH = "/";
class Translate
: public org::apertium::Translate,
public DBus::IntrospectableProxy,
public DBus::ObjectProxy
{
public:
Translate(DBus::Connection& connection, const char* path, const char* name)
: DBus::ObjectProxy(connection, path, name) {
}
};
DBus::BusDispatcher dispatcher;
int main(int argc, char** argv) {
DBus::default_dispatcher = &dispatcher;
DBus::Connection bus = DBus::Connection::SessionBus();
std::stringstream input;
std::string mode;
std::map< ::DBus::String, ::DBus::String> translate_options;
if (argc != 2) {
std::cerr << "usage: dbus_test <mode>" << std::endl;
return 1;
}
mode = std::string(argv[1]);
while (!std::cin.eof() and std::cin) {
std::string str;
std::cin >> str;
input << str << " ";
}
Translate translator(bus, TRANSLATE_OBJECT_PATH, TRANSLATE_SERVICE_NAME);
std::cout << translator.translate(mode, translate_options, input.str())
<< std::endl;
}
To compile this program, you only need to put libdbus-c++'s include directory in your include path and link to libdbus-c++-1. You compile command should look something like this (I installed the library to /usr/local, so update the include directory to match your installation directory):
g++ -I/usr/local/include/dbus-c++-1/ dbus_test.cpp -ldbus-c++-1
That's it!