1 // Copyright 2014 Renato Tegon Forti, Antony Polukhin. 2 // Copyright 2015-2019 Antony Polukhin. 3 // 4 // Distributed under the Boost Software License, Version 1.0. 5 // (See accompanying file LICENSE_1_0.txt 6 // or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 // MinGW related workaround 9 #define BOOST_DLL_FORCE_ALIAS_INSTANTIATION 10 11 #include "../b2_workarounds.hpp" 12 #include "../tutorial4/static_plugin.hpp" 13 #include <boost/dll/runtime_symbol_info.hpp> // for program_location() 14 #include <boost/dll/shared_library.hpp> 15 #include <boost/make_shared.hpp> 16 #include <boost/container/map.hpp> 17 #include <boost/filesystem.hpp> 18 #include <iostream> 19 20 //[plugcpp_plugins_collector_def 21 namespace dll = boost::dll; 22 23 class plugins_collector { 24 // Name => plugin 25 typedef boost::container::map<std::string, dll::shared_library> plugins_t; 26 27 boost::dll::fs::path plugins_directory_; 28 plugins_t plugins_; 29 30 // loads all plugins in plugins_directory_ 31 void load_all(); 32 33 // Gets `my_plugin_api` instance using "create_plugin" or "plugin" imports, 34 // stores plugin with its name in the `plugins_` map. 35 void insert_plugin(BOOST_RV_REF(dll::shared_library) lib); 36 37 public: plugins_collector(const boost::dll::fs::path & plugins_directory)38 plugins_collector(const boost::dll::fs::path& plugins_directory) 39 : plugins_directory_(plugins_directory) 40 { 41 load_all(); 42 } 43 44 void print_plugins() const; 45 46 std::size_t count() const; 47 // ... 48 }; 49 //] 50 51 52 //[plugcpp_plugins_collector_load_all load_all()53void plugins_collector::load_all() { 54 namespace fs = ::boost::dll::fs; 55 typedef fs::path::string_type string_type; 56 const string_type extension = dll::shared_library::suffix().native(); 57 58 // Searching a folder for files with '.so' or '.dll' extension 59 fs::recursive_directory_iterator endit; 60 for (fs::recursive_directory_iterator it(plugins_directory_); it != endit; ++it) { 61 if (!fs::is_regular_file(*it)) { 62 continue; 63 } 64 /*<-*/ 65 if ( !b2_workarounds::is_shared_library((*it).path()) ) { 66 continue; 67 } 68 /*->*/ 69 // We found a file. Trying to load it 70 boost::dll::fs::error_code error; 71 dll::shared_library plugin(it->path(), error); 72 if (error) { 73 continue; 74 } 75 std::cout << "Loaded (" << plugin.native() << "):" << it->path() << '\n'; 76 77 // Gets plugin using "create_plugin" or "plugin" function 78 insert_plugin(boost::move(plugin)); 79 } 80 81 dll::shared_library plugin(dll::program_location()); 82 std::cout << "Loaded self\n"; 83 insert_plugin(boost::move(plugin)); 84 } 85 //] 86 87 //[plugcpp_plugins_collector_insert_plugin insert_plugin(BOOST_RV_REF (dll::shared_library)lib)88void plugins_collector::insert_plugin(BOOST_RV_REF(dll::shared_library) lib) { 89 std::string plugin_name; 90 if (lib.has("create_plugin")) { 91 plugin_name = lib.get_alias<boost::shared_ptr<my_plugin_api>()>("create_plugin")()->name(); 92 } else if (lib.has("plugin")) { 93 plugin_name = lib.get<my_plugin_api>("plugin").name(); 94 } else { 95 return; 96 } 97 98 if (plugins_.find(plugin_name) == plugins_.cend()) { 99 plugins_[plugin_name] = boost::move(lib); 100 } 101 } 102 //] 103 print_plugins() const104void plugins_collector::print_plugins() const { 105 plugins_t::const_iterator const end = plugins_.cend(); 106 for (plugins_t::const_iterator it = plugins_.cbegin(); it != end; ++it) { 107 std::cout << '(' << it->second.native() << "): " << it->first << '\n'; 108 } 109 } 110 count() const111std::size_t plugins_collector::count() const { 112 return plugins_.size(); 113 } 114 115 116 //[plugcpp_load_all main(int argc,char * argv[])117int main(int argc, char* argv[]) { 118 /*<-*/ 119 BOOST_ASSERT(argc >= 3); 120 boost::dll::fs::path path1(argv[1]); 121 for (int i = 2; i < argc; ++i) { 122 boost::dll::fs::path path2(argv[i]); 123 boost::dll::fs::path res; 124 for (boost::dll::fs::path::iterator it1 = path1.begin(), it2 = path2.begin(); 125 it1 != path1.end() && it2 != path2.end() && *it1 == *it2; 126 ++it1, ++it2) 127 { 128 res /= *it1; 129 } 130 131 path1 = res; 132 } 133 134 std::string new_argv = path1.string(); 135 std::cout << "\nPlugins path: " << new_argv << ":\n"; 136 argv[1] = &new_argv[0]; 137 /*->*/ 138 plugins_collector plugins(argv[1]); 139 140 std::cout << "\n\nUnique plugins " << plugins.count() << ":\n"; 141 plugins.print_plugins(); 142 // ... 143 //] 144 BOOST_ASSERT(plugins.count() >= 3); 145 } 146 147