繁体   English   中英

动态库加载的 C++ 依赖注入

[英]C++ Dependency injection with Dynamic library loading

我无法将 C++ 依赖注入库“ boost::di ”与另一个 boost 库一起用于动态加载名为“ Boost.dll ”的库。

我将问题分为两部分 - 首先,测试动态加载,其次,将抽象类绑定到实现(动态加载)。

我能够成功地动态加载库。 但是当我尝试使用依赖注入绑定时,它会报告类模板是预期的但未收到的不匹配。

我在这个 repo 中有一个非常基本的示例代码:https ://bitbucket.org/kobe_la/boost-plugins-prework/src/master/

我真的会使用一些帮助来确定动态加载库的绑定过程。 (请参阅底部的确切错误)

  • 文件ioperation.hpp

     #include <string> class ioperation { public: virtual std::string name() const = 0; virtual float calculate(float x, float y) = 0; virtual ~ioperation() {} };
  • 文件sum.cpp

     #include <boost/config.hpp> #include <boost/dll/alias.hpp> #include <boost/dll/import.hpp> #include "ioperation.hpp" #include <iostream> namespace sum_namespace { class sum: public ioperation { public: sum() { std::cout << "[sum_constructor]" << std::endl; } std::string name() const { return "sum"; } float calculate(float x, float y) { return x + y; } ~sum() { std::cout << "[~sum_destructor]" << std::endl; } // Factory method static boost::shared_ptr<sum> create_sum() { return boost::shared_ptr<sum>( new sum() ); } }; } BOOST_DLL_ALIAS( sum_namespace::sum::create_sum, // <-- this function is exported with... create_sum // <-- ...this alias name )
  • 文件dot_product.cpp

     #include <boost/config.hpp> #include <boost/dll/alias.hpp> #include <boost/dll/import.hpp> #include <iostream> #include "ioperation.hpp" namespace dot_product_namespace { class dot_product: public ioperation { boost::shared_ptr<ioperation> sum_ptr; public: dot_product(boost::shared_ptr<ioperation> &arg) { sum_ptr = arg; std::cout << "[dot_product_constructor]" << std::endl; } std::string name() const { return "dot_product"; } float calculate(float a1, float a2) { //dot product given vector with itself //formula: ab = a1*b1 + a2*b2 return sum_ptr->calculate(a1*a1, a2*a2); } // Factory method static boost::shared_ptr<ioperation> create_dot_product(boost::shared_ptr<ioperation> sum_ptr) { return boost::shared_ptr<ioperation>( new dot_product(sum_ptr) ); } ~dot_product() { std::cout << "[~dot_product_destructor]" << std::endl; } }; }; BOOST_DLL_ALIAS( dot_product_namespace::dot_product::create_dot_product, // <-- this function is exported with... create_dot_product // <-- ...this alias name )
  • 文件application_di.cpp

     #include "boost/shared_ptr.hpp" #include <boost/dll/import.hpp> #include "boost/function.hpp" #include <boost/di.hpp> #include "ioperation.hpp" #include <iostream> namespace di = boost::di; namespace dll = boost::dll; class app { private: boost::shared_ptr<ioperation> ptr_; public: app(boost::shared_ptr<ioperation> ptr) : ptr_(ptr) { std::cout<<"name: " << ptr_->name()<<std::endl; } }; int main(int argc, char* argv[]) { //setting up paths to library(.so) files boost::filesystem::path shared_library_path("."); // argv[1] contains path to directory with our plugin library boost::filesystem::path child_library_path = shared_library_path/"dot_product"; boost::filesystem::path parent_library_path = shared_library_path/"sum"; //defining function types for lib constructors typedef boost::shared_ptr<ioperation> (sum_create_t)(); typedef boost::shared_ptr<ioperation> (dot_product_create_t)(boost::shared_ptr<ioperation>); boost::function<sum_create_t> sum_creator; boost::function<dot_product_create_t> dot_product_creator; //importing SUM lib constructor(takes no arg) sum_creator = boost::dll::import_alias<sum_create_t>( // type of imported symbol must be explicitly specified parent_library_path, // path to library "create_sum", // symbol to import dll::load_mode::append_decorations // do append extensions and prefixes ); //importing DOT_PRODUCT lib constructor(takes 1 arg of ptr to IOPERATION) dot_product_creator = boost::dll::import_alias<dot_product_create_t>( // type of imported symbol must be explicitly specified child_library_path, // path to library "create_dot_product", // symbol to import dll::load_mode::append_decorations // do append extensions and prefixes ); //creating a ptr to SUM object boost::shared_ptr<ioperation> sum_ptr = sum_creator(); //creating a ptr to DOT_PRODUCT object(passing above created SUM object ptr) boost::shared_ptr<ioperation> dot_product_ptr = dot_product_creator(sum_ptr); auto use_sum = true; const auto injector = di::make_injector( di::bind<ioperation>().to([&](const auto& injector) -> boost::shared_ptr<ioperation> { if (use_sum) return injector.template create<boost::shared_ptr<sum_ptr>>(); else return injector.template create<boost::shared_ptr<dot_product_ptr>>(); }) ); injector.create<app>(); }
  • 文件application_main.cpp

     #include "boost/shared_ptr.hpp" #include <boost/dll/import.hpp> #include "boost/function.hpp" #include <iostream> #include "ioperation.hpp" namespace dll = boost::dll; int main(int argc, char* argv[]) { //setting up paths to library(.so) files boost::filesystem::path shared_library_path(argv[1]); // argv[1] contains path to directory with our plugin library boost::filesystem::path child_library_path = shared_library_path/"dot_product"; boost::filesystem::path parent_library_path = shared_library_path/"sum"; //defining function types for lib constructors typedef boost::shared_ptr<ioperation> (sum_create_t)(); typedef boost::shared_ptr<ioperation> (dot_product_create_t)(boost::shared_ptr<ioperation>); boost::function<sum_create_t> sum_creator; boost::function<dot_product_create_t> dot_product_creator; //importing SUM lib constructor(takes no arg) sum_creator = boost::dll::import_alias<sum_create_t>( // type of imported symbol must be explicitly specified parent_library_path, // path to library "create_sum", // symbol to import dll::load_mode::append_decorations // do append extensions and prefixes ); //importing DOT_PRODUCT lib constructor(takes 1 arg of ptr to IOPERATION) dot_product_creator = boost::dll::import_alias<dot_product_create_t>( // type of imported symbol must be explicitly specified child_library_path, // path to library "create_dot_product", // symbol to import dll::load_mode::append_decorations // do append extensions and prefixes ); //creating a ptr to PARENT_PLUGIN_SUM objecti boost::shared_ptr<ioperation> sum_ptr = sum_creator(); //creating a ptr to CHILD_PLUGIN_MULT object(passing above created PARENT_PLUGIN_SUM object ptr) boost::shared_ptr<ioperation> dot_product_ptr = dot_product_creator(sum_ptr); //executing calculate methods for object ptrs std::cout << "Plugin Name: " << sum_ptr->name() << std::endl; std::cout << "sum_ptr->calculate(1, 2)[expected=3]: " << sum_ptr->calculate(1, 2) << std::endl; std::cout << "Plugin Name: " << dot_product_ptr->name() << std::endl; std::cout << "dot_product_ptr->calculate(1, 2)[expected=5]: " << dot_product_ptr->calculate(1, 2) << std::endl; }

以下是观察到的确切错误:

    + echo '=> Compiling libraries and application_main.cpp ...'
    => Compiling libraries and application_main.cpp ...

    + g++ -std=c++14 -fPIC -c -o libsum.o sum.cpp
    + g++ -shared -o libsum.so libsum.o
    + g++ -std=c++14 -fPIC -c -o libdot_product.o dot_product.cpp
    + g++ -shared -o libdot_product.so libdot_product.o
    + g++ -std=c++14 -lboost_filesystem -lboost_system -ldl application_main.cpp -o application_main
    + echo '=> Compilation completed. '
    => Compilation completed. 

    + echo '=> Executing ./application_main .'
    => Executing ./application_main .

    + ./application_main .
    [sum_constructor]
    [dot_product_constructor]
    Plugin Name: sum
    sum_ptr->calculate(1, 2)[expected=3]: 3
    Plugin Name: dot_product
    dot_product_ptr->calculate(1, 2)[expected=5]: 5
    [~dot_product_destructor]
    [~sum_destructor]
    + echo ==================================
    ==================================
    + echo '=> Compiling application_di.cpp ...'

    => Compiling application_di.cpp …
    + g++ application_di.cpp -lboost_filesystem -lboost_system -ldl -o application_di
    application_di.cpp: In lambda function:
    application_di.cpp:62:65: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> class boost::shared_ptr’
        62 |               return injector.template create<boost::shared_ptr<sum_ptr>>();
            |                                                                 ^~~~~~~
    application_di.cpp:62:65: note:   expected a type, got ‘sum_ptr’
    application_di.cpp:64:65: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> class boost::shared_ptr’
        64 |               return injector.template create<boost::shared_ptr<dot_product_ptr>>();
            |                                                                 ^~~~~~~~~~~~~~~
    application_di.cpp:64:65: note:   expected a type, got ‘dot_product_ptr’

共享指针是问题所在。 bind<>模板参数不能是指针或引用类型

有一些关于为什么在bind<>中不允许使用指针的信息: https ://github.com/boost-ext/di/issues/317

我想出了一种绑定依赖项的工作方法:

const auto injector =
    di::make_injector(di::bind<ioperation>().to(
        [=, &use_sum](const auto& injector) -> op_ptr
        {
            return use_sum
                ? sum_creator()
                : dot_product_creator(sum_creator());
        }) //
    );

请注意,只要注入器存在,按值捕获工厂函数就会保留 DLL。 这比通过引用捕获更安全。 通过引用捕获use_sum突出显示注入器是动态的。 如果这不是必需的,那么我会将整个喷油器替换为:

 const auto injector = di::make_injector(di::bind<ioperation>().to( use_sum ? sum_creator() : dot_product_creator(sum_creator())) // );

完整演示

另见 Github: https ://github.com/sehe/boost-plugins-prework

  • 文件ioperation.hpp

     #pragma once #include <boost/shared_ptr.hpp> #include <string> struct ioperation { virtual std::string name() const = 0; virtual float calculate(float x, float y) = 0; virtual ~ioperation() = default; }; using op_ptr = boost::shared_ptr<ioperation>;
  • 文件sum.cpp

     #include <boost/config.hpp> #include <boost/dll/alias.hpp> #include <boost/dll/import.hpp> #include "ioperation.hpp" #include <iostream> namespace sum_namespace { class sum : public ioperation { public: sum() { std::cout << "[sum_constructor]" << std::endl; } std::string name() const { return "sum"; } float calculate(float x, float y) { return x + y; } ~sum() { std::cout << "[~sum_destructor]" << std::endl; } // Factory method static op_ptr create_sum() { return op_ptr(new sum()); } }; } // namespace sum_namespace BOOST_DLL_ALIAS( sum_namespace::sum::create_sum, // <-- this function is exported with... create_sum // <-- ...this alias name )
  • 文件sum.hpp

     #pragma once #include "ioperation.hpp" #include "ioperation.hpp" namespace sum_namespace { struct sum : ioperation { sum(); ~sum() override; std::string name() const override; float calculate(float, float) override; static op_ptr create_sum(); }; } // namespace sum_namespace
  • 文件dot_product.cpp

     #include "dot_product.h" #include <boost/config.hpp> #include <boost/dll/alias.hpp> #include <boost/dll/import.hpp> #include <iostream> namespace dot_product_namespace { dot_product::dot_product(op_ptr& arg) { sum_ptr = arg; std::cout << "[dot_product_constructor]" << std::endl; } std::string dot_product::name() const { return "dot_product"; } float dot_product::calculate(float a1, float a2) { // dot product given vector with itself // formula: ab = a1*b1 + a2*b2 return sum_ptr->calculate(a1 * a1, a2 * a2); } // Factory method /*static*/ op_ptr dot_product::create_dot_product(op_ptr sum_ptr) { return op_ptr(new dot_product(sum_ptr)); } dot_product::~dot_product() { std::cout << "[~dot_product_destructor]" << std::endl; } }; // namespace dot_product_namespace BOOST_DLL_ALIAS(dot_product_namespace::dot_product:: create_dot_product, // <-- this function is exported with... create_dot_product // <-- ...this alias name )
  • 文件dot_product.h

     #pragma once #include "ioperation.hpp" namespace dot_product_namespace { struct dot_product : ioperation { dot_product(op_ptr&); ~dot_product() override; std::string name() const override; float calculate(float, float) override; static op_ptr create_dot_product(op_ptr sum_ptr); private: op_ptr sum_ptr; }; }; // namespace dot_product_namespace
  • 文件application_di.cpp

     #include "boost/function.hpp" #include "ioperation.hpp" #include <boost/di.hpp> #include <boost/dll/import.hpp> #include <iostream> namespace di = boost::di; namespace dll = boost::dll; class app { private: op_ptr ptr_; public: app(boost::shared_ptr<ioperation> ptr) : ptr_(ptr) { std::cout << "name: " << ptr_->name() << std::endl; } }; using boost::filesystem::path; int main(int argc, char** argv) { // setting up paths to library(.so) files path lib_path(argc > 1 ? argv[1] : "."), child_library_path = lib_path / "dot_product", parent_library_path = lib_path / "sum"; // defining function types for lib constructors using sum_create_t = op_ptr(); using dot_product_create_t = op_ptr(op_ptr); // importing SUM lib factory auto sum_creator = boost::dll::import_alias<sum_create_t>( parent_library_path, "create_sum", dll::load_mode::append_decorations); // importing DOT_PRODUCT lib factory auto dot_product_creator = boost::dll::import_alias<dot_product_create_t>( child_library_path, "create_dot_product", dll::load_mode::append_decorations); auto use_sum = true; const auto injector = di::make_injector(di::bind<ioperation>().to( [=, &use_sum](const auto& injector) -> op_ptr { return use_sum ? sum_creator() : dot_product_creator(sum_creator()); }) // ); use_sum = argc > 2; injector.create<app>(); }
  • 文件application_main.cpp

     #include "boost/shared_ptr.hpp" #include <boost/dll/import.hpp> #include "boost/function.hpp" #include <iostream> #include "ioperation.hpp" namespace dll = boost::dll; using boost::filesystem::path; int main(int argc, char** argv) { // setting up paths to library(.so) files path lib_path(argc > 1 ? argv[1] : "."), child_library_path = lib_path / "dot_product", parent_library_path = lib_path / "sum"; // defining function types for lib constructors using sum_create_t = op_ptr(); using dot_product_create_t = op_ptr(op_ptr); // importing SUM lib factory auto sum_creator = dll::import_alias<sum_create_t>( parent_library_path, "create_sum", dll::load_mode::append_decorations); // importing DOT_PRODUCT lib factory auto dot_product_creator = dll::import_alias<dot_product_create_t>( child_library_path, "create_dot_product", dll::load_mode::append_decorations); auto sum_ptr = sum_creator(); auto dot_product_ptr = dot_product_creator(sum_ptr); //executing calculate methods for object ptrs for (op_ptr op : {sum_creator(), dot_product_creator(sum_creator()) }) { std::cout << "\nPlugin Name: " << op->name() << "\n"; std::cout << "calculate(1, 2): " << op->calculate(1, 2) << "\n"; } }
  • 文件compile_n_run.sh

     #!/bin/bash set -e -x -u ./cleanup.sh echo "=> Compiling now..." CPPFLAGS="-std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/" LDFLAGS="" # Required to compile on sehe's machine: #CPPFLAGS="$CPPFLAGS -I /home/sehe/custom/boost-di/include/" #CPPFLAGS="$CPPFLAGS -isystem /home/sehe/custom/superboost/ "; #LDFLAGS="$LDFLAGS -L /home/sehe/custom/superboost/stage/lib" g++ $CPPFLAGS sum.cpp -shared -o libsum.so $LDFLAGS g++ $CPPFLAGS dot_product.cpp -shared -o libdot_product.so $LDFLAGS # add application libraries LDFLAGS="$LDFLAGS -lboost_filesystem -lboost_system -ldl" g++ $CPPFLAGS application_main.cpp -o application_main $LDFLAGS g++ $CPPFLAGS application_di.cpp -o application_di $LDFLAGS ./application_main . ./application_di . use_sum ./application_di . # uses dot_product

输出

使用compile_n_run.sh

+ ./cleanup.sh
removed 'application_main'
removed 'libdot_product.so'
removed 'libsum.so'
=> cleaned up!
+ echo '=> Compiling now...'
=> Compiling now...
+ CPPFLAGS='-std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/'
+ LDFLAGS=
+ g++ -std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/ sum.cpp -shared -o libsum.so
+ g++ -std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/ dot_product.cpp -shared -o libdot_product.so
+ LDFLAGS=' -lboost_filesystem -lboost_system -ldl'
+ g++ -std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/ application_main.cpp -o application_main -lboost_filesystem -lboost_system -ldl
+ g++ -std=c++14 -fPIC -I /home/sehe/custom/boost-di/include/ application_di.cpp -o application_di -lboost_filesystem -lboost_system -ldl
+ ./application_main .
[sum_constructor]
[dot_product_constructor]
[sum_constructor]
[sum_constructor]
[dot_product_constructor]

Plugin Name: sum
calculate(1, 2): 3

Plugin Name: dot_product
calculate(1, 2): 5
[~dot_product_destructor]
[~sum_destructor]
[~sum_destructor]
[~dot_product_destructor]
[~sum_destructor]
+ ./application_di . use_sum
[sum_constructor]
name: sum
[~sum_destructor]
+ ./application_di .
[sum_constructor]
[dot_product_constructor]
name: dot_product
[~dot_product_destructor]
[~sum_destructor]

或更多直播: 在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM