Compiling a C++ D-Bus program
Read the guide to installing the Java 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!