### Build Example Programs Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Enable the build of example programs located in the `examples/` directory. These examples are not installed by default. ```bash cmake .. -DSDBUSCPP_BUILD_EXAMPLES=ON ``` -------------------------------- ### Install Example Executables Source: https://github.com/kistler-group/sdbus-cpp/blob/master/examples/CMakeLists.txt Installs the built server and client executables to the specified destination directory if the SDBUSCPP_INSTALL option is enabled. Components are used for granular installation. ```cmake if(SDBUSCPP_INSTALL) install(TARGETS obj-manager-server DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT sdbus-c++-examples) install(TARGETS obj-manager-client DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT sdbus-c++-examples) endif() ``` -------------------------------- ### Install Documentation Files Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/CMakeLists.txt Installs various documentation-related files to the installation directory. This includes static markdown files, diagrams, and optionally the generated HTML documentation if Doxygen was found and used. ```cmake if(SDBUSCPP_INSTALL) install(FILES sdbus-c++-class-diagram.png sdbus-c++-class-diagram.uml systemd-dbus-config.md using-sdbus-c++.md DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT sdbus-c++-doc) if (SDBUSCPP_BUILD_DOXYGEN_DOCS AND DOXYGEN_FOUND) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL COMPONENT sdbus-c++-doc) endif() endif() ``` -------------------------------- ### Install sdbus-cpp Library Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Use these commands to build and install the sdbus-cpp library after configuring the build. Ensure you have the necessary permissions. ```bash cd build sudo cmake --build . --target install ``` -------------------------------- ### Complete sdbus-c++ Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/proxy.md This example demonstrates creating a D-Bus connection, obtaining a proxy object, and making both synchronous and asynchronous method calls to list services. It includes necessary headers and event loop management. ```cpp #include #include int main() { auto connection = sdbus::createSystemBusConnection(); auto proxy = sdbus::createProxy(*connection, sdbus::ServiceName{"org.freedesktop.DBus"}, sdbus::ObjectPath{"/org/freedesktop/DBus"}); // Synchronous method call std::vector names; proxy->callMethod("ListNames") .onInterface("org.freedesktop.DBus") .storeResultsTo(names); std::cout << "Available services:" << std::endl; for (const auto& name : names) { std::cout << " " << name << std::endl; } // Asynchronous method call proxy->callMethodAsync("ListActivatableNames") .onInterface("org.freedesktop.DBus") .uponReplyInvoke([](std::vector activatable) { std::cout << "Activatable services: " << activatable.size() << std::endl; }); connection->enterEventLoop(); return 0; } ``` -------------------------------- ### Install Unit and Integration Tests Source: https://github.com/kistler-group/sdbus-cpp/blob/master/tests/CMakeLists.txt Installs the unit and integration test executables and their configuration files to the specified destinations. ```cmake install(TARGETS sdbus-c++-unit-tests DESTINATION ${SDBUSCPP_TESTS_INSTALL_PATH} COMPONENT sdbus-c++-test) install(TARGETS sdbus-c++-integration-tests DESTINATION ${SDBUSCPP_TESTS_INSTALL_PATH} COMPONENT sdbus-c++-test) install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/org.sdbuscpp.integrationtests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT sdbus-c++-test) ``` -------------------------------- ### Complete VTable Flag Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/flags.md An example demonstrating the usage of various vtable flags for interface-level behavior, methods, properties, and signals in sdbus-cpp. ```APIDOC ## setupInterface(sdbus::IObject& object) ### Description Sets up an interface with various flags for methods, properties, and signals. ### Method addVTable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cpp object->addVTable({ // Interface-level flags setInterfaceFlags() .markAsPrivileged() .withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsChange), // Methods with various flags registerMethod("PublicMethod") .implementedAs([](auto call, auto result) { result << true; }), registerMethod("PrivateNotification") .implementedAs([](auto call, auto result) { // Handle async notification }) .withNoReply() .markAsPrivileged(), registerMethod("DeprecatedMethod") .implementedAs([](auto call, auto result) { result << "old"; }) .markAsDeprecated(), // Properties with various update behaviors registerProperty("Name") .withGetter([](auto reply, auto call) { reply << "Device Name"; }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::Const), registerProperty("Status") .withGetter([](auto reply, auto call) { reply << "ready"; }) .withSetter([](auto call, auto result) { std::string newStatus; call >> newStatus; result << newStatus; }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsChange), registerProperty("Counter") .withGetter([](auto reply, auto call) { reply << incrementCounter(); }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsInvalidation), // Signals registerSignal("StateChanged") .withParameters("newState"), registerSignal("Deprecated") .withParameters("data") .markAsDeprecated() }).forInterface("com.example.Device"); ``` ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### D-Bus Client Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md This example demonstrates creating a D-Bus proxy, registering signal handlers, and invoking methods. It shows how to handle both successful method calls and errors. Ensure the server-side 'concatenator' service is running. ```c++ #include #include #include #include #include void onConcatenated(sdbus::Signal signal) { std::string concatenatedString; signal >> concatenatedString; std::cout << "Received signal with concatenated string " << concatenatedString << std::endl; } int main(int argc, char *argv[]) { // Create proxy object for the concatenator object on the server side. Since here // we are creating the proxy instance without passing connection to it, the proxy // will create its own connection automatically (to either system bus or session bus, // depending on the context). sdbus::ServiceName destination{"org.sdbuscpp.concatenator"}; sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"}; auto concatenatorProxy = sdbus::createProxy(std::move(destination), std::move(objectPath)); // Let's subscribe for the 'concatenated' signals sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"}; sdbus::SignalName signalName{"concatenated"}; concatenatorProxy->registerSignalHandler(interfaceName, signalName, &onConcatenated); std::vector numbers = {1, 2, 3}; std::string separator = ":"; sdbus::MethodName concatenate{"concatenate"}; // Invoke concatenate on given interface of the object { auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate); method << numbers << separator; auto reply = concatenatorProxy->callMethod(method); std::string result; reply >> result; assert(result == "1:2:3"); } // Invoke concatenate again, this time with no numbers and we shall get an error { auto method = concatenatorProxy->createMethodCall(interfaceName, concatenate); method << std::vector() << separator; try { auto reply = concatenatorProxy->callMethod(method); assert(false); } catch(const sdbus::Error& e) { std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl; } } // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation sleep(1); return 0; } ``` -------------------------------- ### Build and Install sdbus-c++ with CMake Source: https://github.com/kistler-group/sdbus-cpp/blob/master/README.md Standard procedure for building and installing the library using CMake. Ensure you are in the build directory before running the commands. ```bash mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release ${OTHER_CONFIG_FLAGS} cmake --build . sudo cmake --build . --target install ``` -------------------------------- ### Complete sdbus-cpp Client Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/integration.md This C++ client example demonstrates connecting to the system bus, creating a proxy for the Calculator service, registering a signal handler for 'CalculationDone', calling 'Add' and 'Subtract' methods, and retrieving the 'LastResult' property. It includes error handling and manages the D-Bus event loop asynchronously. Ensure the Calculator service is running before executing. ```cpp #include #include int main() { try { auto connection = sdbus::createSystemBusConnection(); // Create proxy to remote Calculator service auto proxy = sdbus::createProxy( *connection, sdbus::ServiceName{"com.example.Calculator"}, sdbus::ObjectPath{"/com/example/Calculator"}); // Register signal handler proxy->onSignal("CalculationDone") .onInterface("com.example.Calculator") .call([](int result, std::string operation) { std::cout << "Calculation (" << operation << ") done: " << result << std::endl; }); // Run event loop in separate thread for signal handling connection->enterEventLoopAsync(); // Call methods int sum = 0; proxy->callMethod("Add") .onInterface("com.example.Calculator") .withArguments(10, 20) .storeResultsTo(sum); std::cout << "10 + 20 = " << sum << std::endl; int difference = 0; proxy->callMethod("Subtract") .onInterface("com.example.Calculator") .withArguments(30, 5) .storeResultsTo(difference); std::cout << "30 - 5 = " << difference << std::endl; // Get property auto lastResult = proxy->getProperty("LastResult") .onInterface("com.example.Calculator"); std::cout << "Last result: " << lastResult.get() << std::endl; // Wait for signal to arrive std::this_thread::sleep_for(std::chrono::seconds(2)); connection->leaveEventLoop(); } catch (const sdbus::Error& e) { std::cerr << "D-Bus error: " << e.getName() << std::endl; std::cerr << "Message: " << e.getMessage() << std::endl; return 1; } return 0; } ``` -------------------------------- ### Complete sdbus-cpp Object Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/object.md This C++ code demonstrates the creation of a D-Bus object adaptor for a counter. It includes registering methods like 'Increment' and 'Reset', a property 'Value', and a signal 'ValueChanged'. The example also shows how to set interface flags and integrate with the D-Bus system bus. ```cpp #include class Counter { int value_ = 0; public: std::unique_ptr exposedObject_; Counter(sdbus::IConnection& conn) { exposedObject_ = sdbus::createObject(conn, sdbus::ObjectPath{"/com/example/Counter"}); exposedObject_->addVTable({ // Methods registerMethod("Increment") .implementedAs([this](auto call, auto result) { value_++; result << value_; exposedObject_->emitSignal("ValueChanged") .onInterface("com.example.Counter") .withArguments(value_); }) .withOutputParamNames({"newValue"}), registerMethod("Reset") .implementedAs([this](auto call, auto result) { value_ = 0; result << value_; }), // Properties registerProperty("Value") .withGetter([this](auto reply, auto call) { reply << value_; }) .withSetter([this](auto call, auto result) { call >> value_; result << value_; }), // Signals registerSignal("ValueChanged") .withParameters("newValue"), // Interface flags setInterfaceFlags().markAsPrivileged() }).forInterface("com.example.Counter"); } }; int main() { auto connection = sdbus::createSystemBusConnection( sdbus::ServiceName{"com.example.Counter"}); connection->enterEventLoopAsync(); Counter counter(*connection); // Application logic... connection->leaveEventLoop(); return 0; } ``` -------------------------------- ### Complete VTable Flag Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/flags.md This comprehensive example demonstrates various flags for interface-level settings, methods, properties, and signals within a sdbus-cpp VTable definition. It includes setting interface privileges, method reply behavior, property update strategies, and marking signals as deprecated. ```cpp #include void setupInterface(sdbus::IObject& object) { object->addVTable({ // Interface-level flags setInterfaceFlags() .markAsPrivileged() .withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsChange), // Methods with various flags registerMethod("PublicMethod") .implementedAs([](auto call, auto result) { result << true; }), registerMethod("PrivateNotification") .implementedAs([](auto call, auto result) { // Handle async notification }) .withNoReply() .markAsPrivileged(), registerMethod("DeprecatedMethod") .implementedAs([](auto call, auto result) { result << "old"; }) .markAsDeprecated(), // Properties with various update behaviors registerProperty("Name") .withGetter([](auto reply, auto call) { reply << "Device Name"; }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::Const), registerProperty("Status") .withGetter([](auto reply, auto call) { reply << "ready"; }) .withSetter([](auto call, auto result) { std::string newStatus; call >> newStatus; result << newStatus; }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsChange), registerProperty("Counter") .withGetter([](auto reply, auto call) { reply << incrementCounter(); }) .withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags::EmitsInvalidation), // Signals registerSignal("StateChanged") .withParameters("newState"), registerSignal("Deprecated") .withParameters("data") .markAsDeprecated() }).forInterface("com.example.Device"); } ``` -------------------------------- ### Set CMAKE_INSTALL_PREFIX to Custom Path Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Specify a custom installation root directory for headers, libraries, and documentation. This is useful for user-specific installations. ```bash cmake .. -DCMAKE_INSTALL_PREFIX=/usr ``` -------------------------------- ### Configure Test Binaries Installation Path Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Specify a custom installation directory for test binaries when `SDBUSCPP_BUILD_TESTS` is enabled. The default path is `${CMAKE_INSTALL_PREFIX}/tests/sdbus-c++`. ```bash cmake .. -DSDBUSCPP_TESTS_INSTALL_PATH=/opt/test/bin ``` -------------------------------- ### Set CMAKE_INSTALL_PREFIX to User Local Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Install the library into the user's local directory. This avoids needing root privileges for installation. ```bash cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local ``` -------------------------------- ### Minimal Production Build Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Performs a minimal production build with shared libraries enabled. Includes steps for configuring, building, and installing. ```bash mkdir build && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON cmake --build . sudo cmake --build . --target install ``` -------------------------------- ### Development Build with Tests and Documentation Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Configures a development build with tests, performance tests, Doxygen documentation, and examples enabled. Includes commands to build, run tests, and generate documentation. ```bash mkdir build && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Debug \ -DSDBUSCPP_BUILD_TESTS=ON \ -DSDBUSCPP_BUILD_PERF_TESTS=ON \ -DSDBUSCPP_BUILD_DOXYGEN_DOCS=ON \ -DSDBUSCPP_BUILD_EXAMPLES=ON cmake --build . cmake --build . --target test # Run tests cmake --build . --target doc # Generate API docs ``` -------------------------------- ### Install Stress Test Components Source: https://github.com/kistler-group/sdbus-cpp/blob/master/tests/CMakeLists.txt Conditionally installs stress test executables and their configuration files if stress tests are enabled. ```cmake install(TARGETS sdbus-c++-stress-tests DESTINATION ${SDBUSCPP_TESTS_INSTALL_PATH} COMPONENT sdbus-c++-test) install(FILES ${STRESSTESTS_SOURCE_DIR}/files/org.sdbuscpp.stresstests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT sdbus-c++-test) ``` -------------------------------- ### D-Bus Signature to C++ Type Examples Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Illustrates the conversion of D-Bus signatures to their corresponding C++ types for method arguments and return values. ```cpp std::map>> ``` ```cpp std::vector ``` ```cpp std::vector> ``` -------------------------------- ### Install Performance Test Components Source: https://github.com/kistler-group/sdbus-cpp/blob/master/tests/CMakeLists.txt Conditionally installs performance test client and server executables and their configuration files if performance tests are enabled. ```cmake install(TARGETS sdbus-c++-perf-tests-client DESTINATION ${SDBUSCPP_TESTS_INSTALL_PATH} COMPONENT sdbus-c++-test) install(TARGETS sdbus-c++-perf-tests-server DESTINATION ${SDBUSCPP_TESTS_INSTALL_PATH} COMPONENT sdbus-c++-test) install(FILES ${PERFTESTS_SOURCE_DIR}/files/org.sdbuscpp.perftests.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d COMPONENT sdbus-c++-test) ``` -------------------------------- ### Direct D-Bus Connection Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Demonstrates setting up a direct, peer-to-peer D-Bus connection using `sdbus::createServerBus` and `sdbus::createDirectBusConnection`. This bypasses the D-Bus daemon and is useful for inter-process communication where a daemon is not desired or available. Ensure to manage the event loop and connection lifetimes appropriately. ```cpp #include "Concatenator.h" #include "ConcatenatorProxy.h" #include #include #include int main(int argc, char *argv[]) { int fds[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, fds); std::unique_ptr serverConnection; std::unique_ptr clientConnection; std::thread t([&]() { serverConnection = sdbus::createServerBus(fds[0]); // This is necessary so that createDirectBusConnection() below does not block serverConnection->enterEventLoopAsync(); }); clientConnection = sdbus::createDirectBusConnection(fds[1]); clientConnection->enterEventLoopAsync(); t.join(); // We can now use connection objects in a familiar way, e.g. create adaptor and proxy objects on them, and exchange messages. // Here, using Concatenator IDL-generated bindings example from chapters above: Concatenator concatenator(*serverConnection, sdbus::ObjectPath{"/org/sdbuscpp/concatenator"}); sdbus::ServiceName emptyDestination; // Destination may be empty in case of direct connections ConcatenatorProxy concatenatorProxy(*clientConnection, std::move(emptyDestination), sdbus::ObjectPath{"/org/sdbuscpp/concatenator"}); // Perform call of concatenate D-Bus method std::vector numbers = {1, 2, 3}; std::string separator = ":"; auto concatenatedString = concatenatorProxy.concatenate(numbers, separator); assert(concatenatedString == "1:2:3"); // Explicitly stop working on socket fd's to avoid "Connection reset by peer" errors clientConnection->leaveEventLoop(); serverConnection->leaveEventLoop(); } ``` -------------------------------- ### Client-side D-Bus Communication with sdbus-c++ Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md This example demonstrates creating a D-Bus proxy, subscribing to signals, and invoking methods on a remote object. It includes error handling for method calls and signal reception. ```c++ #include #include #include #include #include void onConcatenated(const std::string& concatenatedString) { std::cout << "Received signal with concatenated string " << concatenatedString << std::endl; } int main(int argc, char *argv[]) { // Create proxy object for the concatenator object on the server side sdbus::ServiceName destination{"org.sdbuscpp.concatenator"}; sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"}; auto concatenatorProxy = sdbus::createProxy(std::move(destination), std::move(objectPath)); // Let's subscribe for the 'concatenated' signals sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"}; concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([](const std::string& str){ onConcatenated(str); }); std::vector numbers = {1, 2, 3}; std::string separator = ":"; // Invoke concatenate on given interface of the object { std::string concatenatedString; concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(numbers, separator).storeResultsTo(concatenatedString); assert(concatenatedString == "1:2:3"); } // Invoke concatenate again, this time with no numbers and we shall get an error { try { concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(std::vector(), separator); assert(false); } catch(const sdbus::Error& e) { std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl; } } // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation sleep(1); return 0; } ``` -------------------------------- ### Start a D-Bus Service Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/README.md Use this pattern to create a new D-Bus service. It establishes a connection to the system bus, registers an object, and enters the event loop to handle incoming requests. ```cpp auto connection = sdbus::createSystemBusConnection( sdbus::ServiceName{"com.example.Service"}); auto object = sdbus::createObject(*connection, sdbus::ObjectPath{"/com/example/Object"}); object->addVTable({...}).forInterface("com.example.Interface"); connection->enterEventLoop(); ``` -------------------------------- ### Build libsystemd shared library Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Steps to clone, build, and install libsystemd as a shared library for use with sdbus-c++. Ensure you have the necessary build dependencies. ```shell git clone https://github.com/systemd/systemd cd systemd git checkout v242 # or any other recent stable version mkdir build cd build meson --buildtype=release .. # solve systemd dependencies if any pop up, e.g. libmount-dev, libcap, librt... ninja version.h # building version.h target is only necessary in systemd version >= 241 ninja libsystemd.so.0.26.0 # or another version number depending which systemd version you have # finally, manually install the library, header files and libsystemd.pc pkgconfig file ``` -------------------------------- ### sdbus::Variant Usage Examples Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/types.md Demonstrates creating, extracting values from, and type checking sdbus::Variant objects. Also shows usage in property access. ```cpp // Create variants sdbus::Variant intVariant(42); sdbus::Variant stringVariant("hello"); // Extract values int i = intVariant.get(); std::string s = stringVariant.get(); // Type checking if (intVariant.containsValueOfType()) { std::cout << intVariant.get() << std::endl; } // Use in property access (returns Variant) auto value = proxy->getProperty("SomeProperty") .onInterface("com.example.Service"); ``` -------------------------------- ### IConnection::enterEventLoopAsync Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/connection.md Starts the I/O event loop in a separate internal thread. Returns immediately. ```APIDOC ## enterEventLoopAsync() ### Description Starts the I/O event loop in a separate internal thread. Returns immediately. ### Throws sdbus::Error ### Thread Safety Safe to call from multiple threads. ### Example ```cpp connection->enterEventLoopAsync(); // Application code continues... ``` ``` -------------------------------- ### Message Serialization and Deserialization Example Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/message.md Demonstrates how to serialize primitive data types into a message using the `<<` operator and then deserialize them using the `>>` operator. Ensure the message is sealed after serialization and before deserialization. ```cpp sdbus::PlainMessage msg = connection->createPlainMessage(); msg << 42 << "hello" << 3.14; msg.seal(); // Deserialize int i; std::string s; double d; msg >> i >> s >> d; ``` -------------------------------- ### Generate Doxygen API Documentation Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Generate Doxygen API documentation. This requires the Doxygen tool to be installed and the build must be explicitly invoked with the `doc` target. ```bash cmake .. -DSDBUSCPP_BUILD_DOXYGEN_DOCS=ON cmake --build . --target doc ``` -------------------------------- ### sdbus::Struct Usage Examples Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/types.md Illustrates defining, creating, and accessing fields of sdbus::Struct objects using direct access, std::get, and structured bindings. Includes usage with make_struct. ```cpp // Define struct type using Point = sdbus::Struct; using Rectangle = sdbus::Struct; // Create instances Point p1(10.0, 20.0); Point p2(30.0, 40.0); Rectangle rect(p1, p2); // Access fields double x = std::get<0>(p1); double y = p1.get<1>(); // Structured bindings auto [minX, minY] = p1; // With make_struct auto point = sdbus::make_struct(10.0, 20.0); ``` -------------------------------- ### Convenience API: Getting All Properties Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Retrieve all properties of a D-Bus object under a given interface using `IProxy::getAllProperties()` synchronously or asynchronously. ```APIDOC #### Getting all properties In a very analogous way, with both synchronous and asynchronous options, it's possible to read all properties of an object under given interface at once. `IProxy::getAllProperties()` is what you're looking for. ``` -------------------------------- ### Generated C++ Proxy for Properties Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Illustrates how generated C++ proxy classes interact with D-Bus properties for getting and setting values. ```cpp class PropertyProvider_proxy { /*...*/ public: // getting the property value uint32_t status() { return m_object.getProperty("status").onInterface(INTERFACE_NAME).get(); } // setting the property value void status(const uint32_t& value) { m_object.setProperty("status").onInterface(INTERFACE_NAME).toValue(value); } /*...*/ }; ``` -------------------------------- ### Enter Event Loop (Asynchronous) Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/connection.md Starts the I/O event loop in a separate internal thread, returning immediately. This method is safe to call from multiple threads. ```cpp connection->enterEventLoopAsync(); // Application code continues... ``` -------------------------------- ### Self-contained Build with Bundled sd-bus Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Builds sdbus-cpp in a self-contained manner, bundling sd-bus and specifying a custom installation prefix. Supports parallel builds. ```bash mkdir build && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DSDBUSCPP_BUILD_LIBSYSTEMD=ON \ -DSDBUSCPP_LIBSYSTEMD_VERSION=252 \ -DCMAKE_INSTALL_PREFIX=$HOME/sdbus-install cmake --build . --parallel $(nproc) cmake --build . --target install ``` -------------------------------- ### D-Bus Server Implementation with sdbus-c++ Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Implements a D-Bus server that concatenates strings and emits a signal. Requires a D-Bus connection and object setup. ```c++ #include #include #include // Yeah, global variable is ugly, but this is just an example and we want to access // the concatenator instance from within the concatenate method handler to be able // to emit signals. sdbus::IObject* g_concatenator{}; void concatenate(sdbus::MethodCall call) { // Deserialize the collection of numbers from the message std::vector numbers; call >> numbers; // Deserialize separator from the message std::string separator; call >> separator; // Return error if there are no numbers in the collection if (numbers.empty()) throw sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.Concatenator.Error"}, "No numbers provided"); std::string result; for (auto number : numbers) { result += (result.empty() ? std::string() : separator) + std::to_string(number); } // Serialize resulting string to the reply and send the reply to the caller auto reply = call.createReply(); reply << result; reply.send(); // Emit 'concatenated' signal sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"}; sdbus::SignalName signalName{"concatenated"}; auto signal = g_concatenator->createSignal(interfaceName, signalName); signal << result; g_concatenator->emitSignal(signal); } int main(int argc, char *argv[]) { // Create D-Bus connection to (either the session or system) bus and requests a well-known name on it. sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"}; auto connection = sdbus::createBusConnection(serviceName); // Create concatenator D-Bus object. sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"}; auto concatenator = sdbus::createObject(*connection, std::move(objectPath)); g_concatenator = concatenator.get(); // Register D-Bus methods and signals on the concatenator object, and exports the object. sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"}; concatenator->addVTable( sdbus::MethodVTableItem{sdbus::MethodName{"concatenate"}, sdbus::Signature{"ais"}, {}, sdbus::Signature{"s"}, {}, &concatenate, {}} , sdbus::SignalVTableItem{sdbus::MethodName{"concatenated"}, sdbus::Signature{"s"}, {}, {}} ) .forInterface(interfaceName); // Run the I/O event loop on the bus connection. connection->enterEventLoop(); } ``` -------------------------------- ### XML Description of D-Bus Interface Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md An example of a D-Bus interface description in XML format for the Concatenator service. ```xml ``` -------------------------------- ### Implementing Asynchronous D-Bus Method with Basic API Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Implement an asynchronous D-Bus method using the basic sdbus-c++ API. This example demonstrates deserializing arguments, handling errors, creating replies, and emitting signals from a worker thread. The 'call' object is moved to the worker thread for reply creation. ```c++ void concatenate(sdbus::MethodCall call) { // Deserialize the collection of numbers from the message std::vector numbers; call >> numbers; // Deserialize separator from the message std::string separator; call >> separator; // Launch a thread for async execution... std::thread([numbers = std::move(numbers), separator = std::move(separator), call = std::move(call)]() { // Return error if there are no numbers in the collection if (numbers.empty()) { // Let's send the error reply message back to the client auto reply = call.createErrorReply({"org.sdbuscpp.Concatenator.Error", "No numbers provided"}); reply.send(); return; } std::string result; for (auto number : numbers) { result += (result.empty() ? std::string() : separator) + std::to_string(number); } // Let's send the reply message back to the client auto reply = call.createReply(); reply << result; reply.send(); // Emit 'concatenated' signal (creating and emitting signals is thread-safe) sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"}; sdbus::SignalName signalName{"concatenated"}; auto signal = g_concatenator->createSignal(interfaceName, signalName); signal << result; g_concatenator->emitSignal(signal); }).detach(); } ``` -------------------------------- ### Generated C++ Proxy for Asynchronous Property Get Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Shows the C++ proxy code generated for asynchronous property retrieval using a callback mechanism. ```cpp class PropertyProvider_proxy { /*...*/ virtual void onStatusPropertyGetReply(const uint32_t& value, std::optional error) = 0; public: // getting the property value sdbus::PendingAsyncCall status() { return m_object.getPropertyAsync("status").onInterface(INTERFACE_NAME).uponReplyInvoke([this](std::optional error, const sdbus::Variant& value){ this->onStatusPropertyGetReply(value.get(), std::move(error)); }); } // setting the property value void status(const uint32_t& value) { m_object.setProperty("status").onInterface(INTERFACE_NAME).toValue(value); } /*...*/ }; ``` -------------------------------- ### Client-Side Key Entry Points Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/overview.md For client applications, key steps involve creating a connection, creating an object proxy for the target service, calling methods on the proxy, and optionally registering signal handlers. ```cpp // 1. Create Connection → `createSystemBusConnection()` // 2. Create Proxy → `std::make_unique(service, path, connection)` // 3. Call Methods → `proxy.callMethod(methodName).onInterface(...).withArguments(...).storeResultsTo(...)` // 4. Handle Signals → `proxy.registerSignalHandler(interface, signal, handler)` ``` -------------------------------- ### Server-Side Key Entry Points Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/overview.md For server applications, key steps include creating a connection, defining and adding methods/signals to a local object, registering a service name, and entering the event loop. ```cpp // 1. Create Connection → `createSystemBusConnection()`, etc. // 2. Create Local Object → `std::make_unique(path, connection)` // 3. Add Methods/Signals → `object.addVTable({registerMethod(...), ...}).forInterface(...)` // 4. Register Service Name → `connection.requestName(serviceName)` // 5. Enter Event Loop → `connection.enterEventLoop()` or `enterEventLoopAsync()` ``` -------------------------------- ### Concatenator Service using Basic sdbus-c++ API Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md An example of a Concatenator service implemented using the basic sdbus-c++ API layer. This layer requires manual message creation, serialization/deserialization, and sending. ```cpp #include class Concatenator : public sdbus::Adaptor { public: Concatenator(sdbus::IConnection& connection, std::string objectPath) : Adaptor(connection, std::move(objectPath)) { registerAdaptor(); } ~Concatenator() override { unregisterAdaptor(); } private: std::string concatenate(const std::vector& numbers, const std::string& separator) override { std::string result; for (size_t i = 0; i < numbers.size(); ++i) { result += std::to_string(numbers[i]); if (i < numbers.size() - 1) { result += separator; } } emit concatenated(result); return result; } }; int main(int argc, char* argv[]) { auto connection = sdbus::createProxy("org.freedesktop.DBus", "/org/freedesktop/DBus"); connection->callMethod("RequestName").onInterface("org.freedesktop.DBus").withArguments("org.sdbuscpp.concatenator", uint32_t{1}); auto connection = sdbus::createConnection(sdbus::BusType::SYSTEM); Concatenator concatenator(*connection, "/org/sdbuscpp/concatenator"); connection->enterEventLoop(); return 0; } ``` -------------------------------- ### Signal Handler with Error Handling in sdbus-c++ Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md This example shows how to add an optional error parameter to a signal callback handler to detect deserialization failures. This is useful for debugging signal reception issues. ```c++ void onConcatenated(std::optional err, int wrongParameter) { assert(err.has_value()); assert(err->getMessage() == "Failed to deserialize a int32 value"); } ``` -------------------------------- ### Asynchronous Method Call with Awaitable (C++20) Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Demonstrates using `getResultAsAwaitable()` for asynchronous D-Bus calls within C++20 coroutines. This returns an awaitable object that can be `co_await`ed to get the method's results or exceptions. ```APIDOC ## Asynchronous Method Call with Awaitable (C++20) ### Description This snippet shows how to use `getResultAsAwaitable()` for asynchronous D-Bus calls in C++20 coroutines. The `co_await` keyword is used to suspend the coroutine until the D-Bus method reply is received. The result of the `co_await` expression will be the method's return values, or a `sdbus::Error` will be thrown if the call fails. ### Method Signature `callMethodAsync(methodName).onInterface(interfaceName).withArguments(args...).getResultAsAwaitable()` ### Parameters - `methodName` (string): The name of the D-Bus method to call. - `interfaceName` (string): The D-Bus interface name. - `args...`: Arguments to pass to the D-Bus method. - ``: Template arguments specifying the expected return types of the D-Bus method. Use `<>` for void-returning methods, a single type for a single return value, and `std::tuple` for multiple return values. ### Example Usage ```c++ // In a coroutine context: auto result = co_await concatenatorProxy->callMethodAsync("concatenate") .onInterface(interfaceName) .withArguments(numbers, separator) .getResultAsAwaitable(); std::cout << "Got concatenate result: " << result << std::endl; // If an error occurs, sdbus::Error is thrown when co_await completes ``` ### Return Value Returns an awaitable object. When `co_await`ed, it resolves to the D-Bus method's return values or throws a `sdbus::Error` upon failure. ``` -------------------------------- ### Get Object Path Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/object.md Returns the object path of this object. ```cpp [[nodiscard]] const ObjectPath& getObjectPath() const; ``` ```cpp auto path = object->getObjectPath(); std::cout << "Object path: " << path << std::endl; ``` -------------------------------- ### Async Method Call with Awaitable (C++20 Coroutines) Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md For C++20 coroutines, use `getResultAsAwaitable` to get an awaitable object. This allows for non-blocking asynchronous operations within coroutines. An `sdbus::Error` is thrown upon completion if the D-Bus call resulted in an error. ```cpp // In a coroutine context: auto result = co_await concatenatorProxy->callMethodAsync("concatenate") .onInterface(interfaceName) .withArguments(numbers, separator) .getResultAsAwaitable(); std::cout << "Got concatenate result: " << result << std::endl; // If an error occurs, sdbus::Error is thrown when co_await completes ``` -------------------------------- ### Include sdbus-c++ Documentation in Build Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Enable the inclusion of sdbus-c++ documentation files and tutorials in the build process. This option also enables the `SDBUSCPP_BUILD_DOXYGEN_DOCS` sub-option. ```bash cmake .. -DSDBUSCPP_BUILD_DOCS=ON ``` -------------------------------- ### Publish D-Bus Service with sdbus-c++ Source: https://github.com/kistler-group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md Create a D-Bus connection, instantiate the adaptor class, and enter the event loop to publish the service. Ensure the service name and object path are correctly defined. ```cpp #include "Concatenator.h" int main(int argc, char *argv[]) { // Create D-Bus connection to (either the system or session) bus and request a well-known name on it. sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"}; auto connection = sdbus::createBusConnection(serviceName); // Create concatenator D-Bus object. sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"}; Concatenator concatenator(*connection, std::move(objectPath)); // Run the loop on the connection. connection->enterEventLoop(); } ``` -------------------------------- ### Get Object Path Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/proxy.md Obtain the object path of the remote D-Bus object using getObjectPath(). ```cpp [[nodiscard]] const ObjectPath& getObjectPath() const; ``` ```cpp auto path = proxy->getObjectPath(); std::cout << "Remote object: " << path << std::endl; ``` -------------------------------- ### Select sd-bus Implementation Library Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/configuration.md Choose which sd-bus implementation library to search for using pkg-config when `SDBUSCPP_BUILD_LIBSYSTEMD` is disabled. Options include `default`, `systemd`, `elogind`, and `basu`. ```bash cmake .. -DSDBUSCPP_SDBUS_LIB=elogind ``` ```bash cmake .. -DSDBUSCPP_SDBUS_LIB=basu ``` -------------------------------- ### Get D-Bus Connection Source: https://github.com/kistler-group/sdbus-cpp/blob/master/_autodocs/proxy.md Retrieve a reference to the underlying D-Bus connection used by the proxy with getConnection(). ```cpp [[nodiscard]] sdbus::IConnection& getConnection() const; ``` ```cpp auto& conn = proxy->getConnection(); ```