📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の26版が非表示)
42行目: 42行目:
sdbus-c++ライブラリはsd-busライブラリを使用しているが、必ずしもSystemdに制約されているわけではなく、Systemd以外の環境でも完璧に使用することができる。<br>
sdbus-c++ライブラリはsd-busライブラリを使用しているが、必ずしもSystemdに制約されているわけではなく、Systemd以外の環境でも完璧に使用することができる。<br>
<br>
<br>
sdbus-c++ライブラリの詳細な使用方法を知りたい場合は、[https://kistler-group.github.io/sdbus-cpp/docs/using-sdbus-c++.html sdbus-c++ライブラリの公式Webサイト]を参照すること。<br>
<br>
==== sdbus-c++ライブラリのライセンス ====
sdbus-c++ライブラリは、LGPL 2.1でライセンスされている。<br>
ただし、ライブラリのヘッダファイルではLGPL Exception version 1.0ライセンスもあり、これは、以下に示すようなことを許可している。<br>
<br>
LGPL 2.1に対する追加的な許可として、「ライブラリを使用する作品」のオブジェクトコード形式は、ライブラリの一部であるヘッダファイルの素材を組み込んでもよい。
あなたは、そのようなオブジェクトコードを、あなたが選択した条件の下で頒布することができる。
(i) ライブラリのヘッダファイルが変更されていないこと。
(ii) 組み込まれる内容が、数値パラメータ、データ構造のレイアウト、アクセサ、マクロ、インライン関数、およびテンプレートに限定されていること。
(iii) LGPL 2.1の第6項の条項を遵守していること。
ただし、そのような改変が、
(i) 数値パラメータ
(ii) データ構造のレイアウト
(iii) アクセサ
(iv) 長さが5行以下の小さなマクロ、テンプレート、インライン関数に限定される場合
はこの限りではない。
さらに、ライブラリの改変バージョンにこの追加許可を適用する必要ない。
<br>
==== sdbus-c++ライブラリのインストール ====
==== sdbus-c++ライブラリのインストール ====
===== パッケージ管理システムからインストール =====
# RHEL (EPELリポジトリが必要)
sudo dnf install sdbus-cpp-devel
# SUSE
sudo zypper install sdbus-cpp-devel
<br>
===== ソースコードからインストール =====
sdbus-c++ライブラリのビルドに必要なライブラリをインストールする。<br>
sdbus-c++ライブラリのビルドに必要なライブラリをインストールする。<br>
# RHEL
sudo dnf install pkg-config make cmake gcc gcc-c++ libcap-devel expat-devel systemd-devel
                  doxygen  # ドキュメントもビルドする場合
  # SUSE
  # SUSE
  sudo zypper install pkg-config make cmake gcc gcc-c++ expat-devel systemd-devel
  sudo zypper install pkg-config make cmake gcc gcc-c++ libcap-devel libexpat-devel libmount-devel systemd-devel
                    doxygen  # ドキュメントもビルドする場合
<br>
<br>
[https://github.com/Kistler-Group/sdbus-cpp sdbus-c++ライブラリのGithub]にアクセスして、ソースコードをダウンロードする。<br>
[https://github.com/Kistler-Group/sdbus-cpp sdbus-c++ライブラリのGithub]にアクセスして、ソースコードをダウンロードする。<br>
57行目: 94行目:
<br>
<br>
sdbus-c++ライブラリをビルドおよびインストールする。<br>  
sdbus-c++ライブラリをビルドおよびインストールする。<br>  
  cmake -DCMAKE_INSTALL_PREFIX=<sdbus-c++ライブラリのインストールディレクトリ>  \
  cmake -DCMAKE_C_COMPILER=<GCC 8以降のGCCコンパイラのパス>  \
       -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_CXX_COMPILER=<G++ 8以降のG++コンパイラのパス> \
       -DBUILD_CODE_GEN=ON        \
      -DCMAKE_INSTALL_PREFIX=<sdbus-c++ライブラリのインストールディレクトリ>  \
       -DBUILD_DOC=ON             \
       -DCMAKE_BUILD_TYPE=Release       \
       -DBUILD_EXAMPLES=ON       \
       -DSDBUSCPP_BUILD_CODEGEN=ON       \
       -DSDBUSCPP_BUILD_EXAMPLES=ON      \
       -DSDBUSCPP_BUILD_DOCS=ON         \
       -DSDBUSCPP_BUILD_DOXYGEN_DOCS=ON \ # Doxygenでドキュメントを生成する場合
       ..
       ..
   
   
67行目: 107行目:
  make install
  make install
<br>
<br>
==== 使用例 : Systemdサービスユニットの開始 ====
==== 使用例 : Systemdサービスユニットの開始 ====
以下の例では、sdbus-c++ライブラリを使用して、<u>sudo systemctl start smb</u>コマンドと同等の操作を行っている。<br>
以下の例では、sdbus-c++ライブラリを使用して、<u>sudo systemctl start smb</u>コマンドと同等の操作を行っている。<br>
D-Bus経由でSystemdと直接通信するため、より柔軟で、プログラム内から制御できるようになっている。<br>
D-Bus経由でSystemdと直接通信するため、より柔軟で、プログラム内から制御できるようになっている。<br>
<br>
<br>
ただし、さんぷるコードを実行するには、適切な権限が必要となる。<br>
ただし、サンプルコードを実行するには、適切な権限が必要となる。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
#include <iostream>
#include <string>
  #include <sdbus-c++/sdbus-c++.h>
  #include <sdbus-c++/sdbus-c++.h>
#include <iostream>
   
   
  int main()
// Systemdサービスはシグナルを送信しないため、今回は使用しない
// #include <atomic>
// #include <chrono>
// #include <thread>
// std::atomic<bool> g_keep_running(false);
// UnitStateChangedシグナルハンドラ
// ただし、Systemdサービスはシグナルを送信しないため、今回は定義しない
// void onUnitStateChanged(sdbus::Signal signal)
// {
//    std::string unitName, newState, oldState;
//    signal >> unitName >> newState >> oldState;
//    std::cout << "Unit " << unitName << " changed state from " << oldState << " to " << newState << std::endl;
//    if (unitName == "smb.service" && (newState == "active" || newState == "failed")) {
//        g_keep_running.store(true);
//    }
// }
// smb.serviceが正常に開始されているかどうかを確認する
bool checkServiceStatus(sdbus::IProxy &systemdProxy, sdbus::InterfaceName &interfaceName, const std::string &serviceName)
{
    try {
      // smb.serviceのユニットパスを取得する
      sdbus::MethodName methodName{"GetUnit"};
      auto method = systemdProxy.createMethodCall(interfaceName, methodName);
      method << serviceName;
      auto reply = systemdProxy.callMethod(method);
      sdbus::ObjectPath unitPath;
      reply >> unitPath;
      // 取得したsmb.serviceのユニットパスを使用して、smb.serviceの開始状態を取得
      /// D-Busサービス名は、"org.freedesktop.systemd1"
      /// D-Busオブジェクト名は、smb.serviceのユニットパス
      auto unitProxy = sdbus::createProxy(systemdProxy.getConnection(), std::move(sdbus::ServiceName{"org.freedesktop.systemd1"}), unitPath);
      /// D-Busインターフェース名は、"org.freedesktop.DBus.Properties"
      /// D-Busインターフェースメソッド名は、"Get"
      auto getProperty = unitProxy->createMethodCall(sdbus::InterfaceName{"org.freedesktop.DBus.Properties"}, sdbus::MethodName{"Get"});
     
      /// D-Busインターフェースメソッド"Get"の引数を指定
      getProperty << "org.freedesktop.systemd1.Unit" << "ActiveState";
      /// D-Busインターフェースメソッドを実行して、戻り値を取得
      auto propertyReply = unitProxy->callMethod(getProperty);
      /// 戻り値は文字列型であるため、文字列型に変換
      /// smb.serviceが正常に開始されている場合は、文字列は"active"となる
      sdbus::Variant variant;
      propertyReply >> variant;
      std::string state = variant.get<std::string>();
      return (state == "active");
    }
    catch (const sdbus::Error &e) {
      // sdbus::Errorをキャッチしてエラーメッセージを表示
      std::cerr << "Error checking service status: " << e.getName() << " - " << e.getMessage() << std::endl;
      return false;
    }
    catch (const std::exception &e) {
      // std::exceptionをキャッチして一般エラーを処理
      std::cerr << "Error: " << e.what() << std::endl;
      return false;
    }
}
  int main(int argc, char *argv[])
  {
  {
    // システムバスへの接続を作成
    auto connection = sdbus::createSystemBusConnection();
    // Systemdサービスのマネージャーインターフェースへのプロキシオブジェクトを作成
    sdbus::ServiceName destination("org.freedesktop.systemd1");
    sdbus::ObjectPath  objectPath("/org/freedesktop/systemd1");
    auto systemdProxy = sdbus::createProxy(*connection, std::move(destination), std::move(objectPath));
    // D-Busインターフェース名を指定
    sdbus::InterfaceName interfaceName("org.freedesktop.systemd1.Manager");
    // UnitStateChangedシグナルのハンドラを登録
    // ただし、Systemdサービスはシグナルを送信しないため、今回は設定しない
    //sdbus::SignalName    signalName("UnitStateChanged");
    //systemdProxy->registerSignalHandler(interfaceName, signalName, &onUnitStateChanged);
     try {
     try {
        // D-Busへの接続を作成
      // "StartUnit"はSystemdサービスのメソッド名
        auto connection = sdbus::createSystemBusConnection();
      sdbus::MethodName methodName{"StartUnit"};
      auto method = systemdProxy->createMethodCall(interfaceName, methodName);
      // Systemdサービスはシグナルを送信しないため、今回は定義しない
      //systemdProxy->uponSignal("JobRemoved")
      //              .onInterface("org.freedesktop.systemd1.Manager")
      //              .call(&onUnitStateChanged);
 
      // D-Busサービスを実行する
      // "smb.service"は開始するSystemdサービス名
      // "replace"はSystemdサービスの起動モード
      method << "smb.service" << "replace";
      auto reply = systemdProxy->callMethod(method);
   
   
        // Systemdのマネージャーインターフェースへのプロキシオブジェクトを作成
      // または、以下に示す方法でもD-Busサービスを実行することができる
        auto proxy = sdbus::createProxy(*connection,
      //systemdProxy->callMethod("StartUnit")
                                        "org.freedesktop.systemd1",
      //              .onInterface("org.freedesktop.systemd1.Manager")
                                        "/org/freedesktop/systemd1");
      //             .withArguments("smb.service", "replace");
   
   
        // StartUnitメソッドを呼び出してsmbサービスを開始
      // Systmedサービスでsmb.service (D-Busサービス) を開始する場合は、ジョブ番号の値が返る
        // "StartUnit"はSystemdサービスのメソッド名
      sdbus::ObjectPath jobPath;
        // "org.freedesktop.systemd1.Manager"はD-Busインターフェース名
      reply >> jobPath;
        // "smb.service"は開始するSystemdサービス名
      std::cout << "StartUnit job path: " << jobPath << std::endl;
        // "replace"はSystemdサービスの起動モード
        proxy->callMethod("StartUnit")
              .onInterface("org.freedesktop.systemd1.Manager")
              .withArguments("smb.service", "replace")
              .storeResultsTo();
   
   
        std::cout << "smb service started successfully." << std::endl;
      // イベントループを開始
      // Systemdサービスはシグナルを送信しないため、今回は使用しない
      //while (g_keep_running) {
      //  connection->processPendingEvent();
      //  std::this_thread::sleep_for(std::chrono::milliseconds(100));  // 100[mS]のスリープ
      //                                                                // これにより、CPUの過剰な使用を避けつつ適度な応答性を維持
      //}
      // smb.service (D-Busサービス) が正常に開始されたかどうかを確認する
      std::string serviceName = "smb.service";
      if (checkServiceStatus(*systemdProxy, interfaceName, serviceName)) {
          std::cout << "Service " << serviceName << " state: " << "avtive" << std::endl;
      }
     }
     }
     catch (const sdbus::Error &e) {
     catch (const sdbus::Error &e) {
       // sdbus::Errorをキャッチしてエラーメッセージを表示
       // sdbus::Errorをキャッチしてエラーメッセージを表示
       std::cerr << "D-Bus error: " << e.what() << std::endl;
       std::cerr << "Error starting smb.service: " << e.getName() << " - " << e.getMessage() << std::endl;
       return -1;
       return -1;
     }
     }
114行目: 259行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
<code>processPendingEvent</code>メソッドの意味を以下に示す。<br>
* イベント処理
*: D-Busシステムから到着した保留中のイベントを1つ処理する。
*: これには、受信したシグナルやメソッド呼び出しの応答などが含まれる。
* ノンブロッキング動作
*: processPendingEventメソッドは、通常、ノンブロッキングで動作する。
*: つまり、処理すべきイベントがない場合、即座に制御を返す。
* シングルイベント処理
*: 1回の呼び出しで1つのイベントのみを処理する。
*: 複数のイベントを処理するには、このメソッドを繰り返し呼び出す必要がある。
<br>
==== 使用例 : ユーザ定義のD-Busサービスの実行 ====
==== 使用例 : ユーザ定義のD-Busサービスの実行 ====
===== D-Busサービス =====
===== D-Busサービス =====
158行目: 315行目:
<u>sdbus-c++ライブラリは効率的な引数の受け渡しを行うよう設計されているため、大きなオブジェクトは自動的に参照として扱われる。</u><br>
<u>sdbus-c++ライブラリは効率的な引数の受け渡しを行うよう設計されているため、大きなオブジェクトは自動的に参照として扱われる。</u><br>
<br>
<br>
===== D-Busヘルパーファイル =====
===== sdbus-c++-xml2cppツール (スタブジェネレータ) の実行 =====
<u>まず、D-Busヘルパー実行ファイルを作成する。</u><br>
<u>次に、上記のDBusインターフェース定義ファイルからC++ヘッダファイルを自動生成する。</u><br>
<br>
sdbus-c++ライブラリには、XMLファイルからC++のソースコードを生成するツールであるsdbus-c++-xml2cppツール (スタブジェネレータ) が存在する。<br>
このツールは、D-Busインタフェースを記述したXMLファイルを受け取り、そのインタフェースを経由して呼び出すことができるC++ヘッダファイルを自動生成するものである。<br>
この自動生成されたC++ヘッダファイルは、D-Bus経由の呼び出しをサービスのプロバイダに転送して、結果を呼び出し元に返す役割がある。<br>
<br>
サービスを実装するサーバは、<code>--adaptor</code>オプションで生成されたヘッダファイルのインターフェイスクラスから派生したクラスを定義して、そのメソッドを実装する必要がある。<br>
<br>
以下のコマンド例は、sdbus-c++-xml2cppツールを実行して、D-Busのサーバ側 (ヘルパー実行ファイル) のC++ヘッダファイルを自動生成している。<br>
sdbus-c++-xml2cpp <D-Busインターフェース定義ファイル名 (XMLファイル)> \
                  --adaptor=<生成するアダプタのヘッダファイル名>
# 例 :
sdbus-c++-xml2cpp org.example.mochiu.xml    \
                  --adaptor=MochiuAdaptor.h
<br>
 
===== D-Busのサーバ側 (ヘルパー実行ファイル) =====
<u>次に、D-Busのサーバ側 (ヘルパー実行ファイル) を作成する。</u><br>
<br>
<u>上記で自動生成されたC++ヘッダファイルを、ヘルパー実行ファイルのソースコードにインクルードする。</u>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // 例: mochiu_helper.hファイル
  // 例: MochiuHelper.hファイル
   
   
  #ifndef MOCHIU_HELPER_H
#include "MochiuAdapter.h"  // 生成されたアダプタヘッダをインクルード
  #define MOCHIU_HELPER_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// 例: MochiuHelper.hファイル
  #ifndef MOCHIUHELPER_H
  #define MOCHIUHELPER_H
   
   
  #include <sdbus-c++/sdbus-c++.h>
  #include <sdbus-c++/sdbus-c++.h>
  #include <iostream>
  #include <iostream>
#include <cstring>
  #include "MochiuAdapter.h"  // 生成されたアダプタヘッダをインクルード
#include <memory>
  #include "mochiu_adaptor.h"  // 生成されたプロキシヘッダをインクルード
// アダプタ名を明示的に指定しない場合は、以下に示すようなクラス継承の記述でも可能
 
// class MochiuHelper : public org::example::mochiu::method_adaptor
  class MochiuHelper : public MochiuAdaptor
  class MochiuHelper : public MochiuAdaptor
  {
  {
  public:
  public:
     MochiuHelper(sdbus::IConnection &connection, const std::string &objectPath) : MochiuAdaptor(connection, objectPath)
     MochiuHelper(sdbus::IConnection& connection, std::string objectPath) : MochiuAdaptor(connection, std::move(objectPath))
     {}
     {
    }
   
   
     // func1メソッドの実装
     // func1メソッドの実装
     int func1(const int &arg1, const std::string &arg2) override
     int func1(const int32_t& arg1, const std::string& arg2) override
     {
     {
       std::cout << "func1 called with arg1: " << arg1 << " and arg2: " << arg2 << std::endl;
       std::cout << "func1 called with args: " << arg1 << ", " << arg2 << std::endl;
       return arg1 * 2;
       return arg1 * 2; // 例: 入力値の2倍を返す
     }
     }
  };
  };
   
   
  class MochiuService
  #endif // MOCHIUHELPER_H </syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// 例: MochiuHelper.cppファイル
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <future>
#include <chrono>
#include "MochiuHelper.h"
// イベントループを実行し、60秒後に終了するための関数
void runEventLoopWithTimeout(std::shared_ptr<sdbus::IConnection> connection)
  {
  {
private:
    // 60秒後に終了するための非同期タスクを作成
     std::unique_ptr<sdbus::IConnection> m_connection;
     auto future = std::async(std::launch::async, []{
    std::unique_ptr<MochiuHelper> m_helper;
      std::this_thread::sleep_for(std::chrono::seconds(60));
    });
   
   
public:
    // イベントループを開始
     MochiuService() : m_connection(sdbus::createSessionBusConnection("org.example.mochiu")),
     while (future.wait_for(std::chrono::seconds(0)) == std::future_status::timeout) {
                      m_helper(std::make_unique<MochiuHelper>(*m_connection, "/org/example/mochiu"))
      connection->processPendingRequest();
    {
        m_connection->enterEventLoop();
     }
     }
};
   
   
  #endif // MOCHIU_HELPER_H
    std::cout << "60 seconds timeout reached. Exiting..." << std::endl;
  </syntaxhighlight>
  }
<br>
<u>次に、上記のDBusインターフェース定義ファイルからC++コードを生成する。</u><br>
int main()
sdbus-c++ライブラリには、XMLファイルからC++のソースコードを生成するツールが付属している。 (sdbus-c++-xml2cppファイル)<br>
  {
sdbus-c++-xml2cppで生成されたソースコードを使用することにより、型安全性が向上して、D-Busインターフェースの使用がより簡単になる。<br>
    try {
<br>
      // システムバスを接続する場合
以下に示すコマンドを実行して、<クライアント側のソースコード>と<サーバ側のソースコード) を生成する。<br>
      auto connection = sdbus::createSystemBusConnection();
  sdbus-c++-xml2cpp <D-Busインターフェース定義ファイル名 (XMLファイル)> \
                  --proxy=<D-Busインターフェースメソッドが記述されたヘルパー実行ファイル側のヘッダファイル名 (プロキシヘッダ)> \
      // セッションバスを接続する場合
                  --adaptor=<生成するアダプターヘッダファイル名>
      //auto connection = sdbus::createSessionBusConnection();
   
      // D-Busサービス名を指定
      connection->requestName("org.example.mochiu");
 
      // D-Busオブジェクトの作成
      MochiuHelper mochiuHelper(*connection, "/org/example/mochiu");
   
   
# 例 :
      // タイムアウト付きでイベントループを実行
sdbus-c++-xml2cpp org.example.mochiu.xml \
      runEventLoopWithTimeout(connection);
                  --proxy=mochiu_helper.h \
    }
                  --adaptor=mochiu_adaptor.h
    catch (const sdbus::Error& e) {
<br>
      std::cerr << "D-Bus error: " << e.what() << std::endl;
<u>最後に、生成されたソースコードを上記のヘルパー実行ファイルのソースコードに統合する。</u>
      return -1;
<syntaxhighlight lang="c++">
    }
// 例: mochiu_header.hファイル
    catch (const std::exception& e) {
      std::cerr << "Error: " << e.what() << std::endl;
      return -1;
    }
   
   
  #include "mochiu_adaptor.h"  // 生成されたプロキシヘッダをインクルード
    return 0;
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>


===== D-Busの呼び出し側 =====
===== D-Busのクライアント側 (呼び出し側) =====
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <sdbus-c++/sdbus-c++.h>
  #include <sdbus-c++/sdbus-c++.h>
234行目: 438行目:
  {
  {
     try {
     try {
      // システムバスへの接続を作成する場合
      auto connection = sdbus::createSystemBusConnection();
       // セッションバスへの接続を作成する場合
       // セッションバスへの接続を作成する場合
      auto connection = sdbus::createSessionBusConnection();
       //auto connection = sdbus::createSessionBusConnection();
      // システムバスへの接続を作成する場合
       //auto connection = sdbus::createSystemBusConnection();
   
   
       // 指定されたD-Busサービスとオブジェクトへのプロキシオブジェクトを作成
       // 指定されたD-Busサービスとオブジェクトのプロキシオブジェクトを作成
       auto proxy = sdbus::createProxy(*connection,
       auto proxy = sdbus::createProxy(*connection,
                                       "org.example.mochiu",  // D-Busサービス名
                                       sdbus::ServiceName{"org.example.mochiu"},  // D-Busサービス名
                                       "/org/example/mochiu" // D-Busオブジェクト名
                                       sdbus::ObjectPath{"/org/example/mochiu"// D-Busオブジェクト名
       );
       );
   
   
251行目: 455行目:
   
   
       // D-Busインターフェースメソッド (func1) を呼び出して、戻り値を受け取る
       // D-Busインターフェースメソッド (func1) を呼び出して、戻り値を受け取る
       auto result = proxy->callMethod("func1")                       // D-Busインターフェースメソッド名
       auto result = proxy->callMethod(sdbus::MethodName{"func1"})                           // D-Busインターフェースメソッド名
                             .onInterface("org.example.mochiu.method")  // D-Busインターフェース名
                             .onInterface(sdbus::InterfaceName{"org.example.mochiu.method"})  // D-Busインターフェース名
                             .withArguments(arg1, arg2)                 // 引数を渡す
                             .withArguments(arg1, arg2)                                       // 引数を指定
                             .returnValue<int>();                       // int型の戻り値を受け取る
                             .returnValue<int>();                                             // 戻り値の型を指定
   
   
       std::cout << "Method 'func1' called successfully." << std::endl;
       std::cout << "Method 'func1' called successfully." << std::endl;
294行目: 498行目:
<br><br>
<br><br>


{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]