Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <pluginlib/class_loader.h>
00031 #include <ros/console.h>
00032 #include <iostream>
00033 #include <vector>
00034 #include <string>
00035 #include <fstream>
00036 #include <sstream>
00037 #include <dlfcn.h>
00038
00039 using std::cout;
00040 using std::endl;
00041 using std::vector;
00042 using std::string;
00043
00044 vector<string> g_cli_arguments;
00045 void* g_class_loader_library_handle = NULL;
00046
00047
00048 void processUserCommand();
00049 void handleFindPluginRequest();
00050 void handleListPluginsRequest();
00051 void handleLoadPluginRequest();
00052
00053
00054 vector<string> getCLIArguments();
00055 void setCLIArguments(int argc, char* argv[]);
00056 bool verifyCLIArguments();
00057
00058 string baseClass(){return(getCLIArguments().at(1));}
00059 string baseClassHeader(){return(getCLIArguments().at(2));}
00060 string packageName(){return(getCLIArguments().at(3));}
00061 string commandVerb(){return(getCLIArguments().at(4));}
00062 string pluginName(){return(getCLIArguments().at(5));}
00063
00064
00065 string callCommandLine(const char* cmd);
00066 string determineIncludePathsForBaseClassHeaderDependencies();
00067 void generateAndLoadTypedPluginInterface();
00068 void generateFile(string filename, string contents);
00069 string generatedSharedLibrary(){return "libTypedPluginInterface.so";}
00070 string generatedObjFile(){return "typedPluginInterface.o";}
00071 string generatedCppFile(){return "typedPluginInterface.cpp";}
00072 string getPluginlibSharedFolder();
00073 string getTypedClassLoaderTemplate();
00074 string getTypedClassLoaderTemplateWithBaseSet();
00075 vector<string> parseToStringVector(std::string newline_delimited_str);
00076 string stripNewlineCharacters(const std::string& s);
00077 string templateCppFileWithoutExtension(){return "typedPluginInterface";}
00078 string templateCppFile(){return templateCppFileWithoutExtension() + ".cpp";}
00079 string templateCppFileAbsolutePath(){return getPluginlibSharedFolder() + "/" + templateCppFile();}
00080
00081
00082 int main(int argc, char* argv[])
00083
00084 {
00085 cout << "plugin_tool - A command line tool for pluginlib testing" << endl;
00086 cout << "-------------------------------------------------------" << endl;
00087
00088 setCLIArguments(argc, argv);
00089 if(!verifyCLIArguments())
00090 {
00091 cout << "Error: Invalid arguments passed to plugin_tool." << endl;
00092 exit(-1);
00093 }
00094
00095 cout << "Base class = " << baseClass() << endl;
00096 cout << "Package name = " << packageName() << endl << endl;
00097
00098 generateAndLoadTypedPluginInterface();
00099 processUserCommand();
00100
00101 return 0;
00102 }
00103
00104 std::string callCommandLine(const char* cmd)
00105
00106 {
00107 FILE* pipe = popen(cmd, "r");
00108 if (!pipe)
00109 return "ERROR";
00110 char buffer[128];
00111 std::string result = "";
00112 while(!feof(pipe))
00113 {
00114 if(fgets(buffer, 128, pipe) != NULL)
00115 result += buffer;
00116 }
00117 pclose(pipe);
00118 return result;
00119 }
00120
00121 string determineIncludePathsForBaseClassHeaderDependencies()
00122
00123 {
00124 string cmd = "rospack cflags-only-I " + packageName();
00125 return(stripNewlineCharacters(callCommandLine(cmd.c_str())));
00126 }
00127
00128 void generateAndLoadTypedPluginInterface()
00129
00130 {
00131 cout << "Generating typed plugin interface cpp..." << endl;
00132 string code = getTypedClassLoaderTemplateWithBaseSet();
00133 cout << "***************************************************" << endl;
00134 cout << code << endl;
00135 cout << "***************************************************" << endl;
00136
00137 cout << "Outputting to file " << templateCppFile() << "..." << endl;
00138 generateFile(generatedCppFile(), code);
00139
00140 cout << "Building interface shared object..." << endl;
00141 string cmd1 = "g++ -fPIC -I" + determineIncludePathsForBaseClassHeaderDependencies() + " -c " + generatedCppFile();
00142 string cmd2 = "g++ -shared -o " + generatedSharedLibrary() + " " + generatedObjFile();
00143
00144 cout << "Command 1 = " << cmd1 << endl;
00145 cout << "Command 2 = " << cmd2 << endl;
00146
00147 if(-1 == system(cmd1.c_str()))
00148 {
00149 cout << "Error: Failed to compile interface." << endl;
00150 exit(-1);
00151 }
00152 else
00153 {
00154 cout << "Interface compiled to an object file, attempting to build..." << endl;
00155 if(-1 == system(cmd2.c_str()))
00156 {
00157 cout << "Error: Failed to build shared object." << endl;
00158 exit(-1);
00159 }
00160 else
00161 cout << "Build of shared object succeeded." << endl;
00162
00163 }
00164
00165 cout << "Loading shared object into memory." << endl;
00166 g_class_loader_library_handle = dlopen("libTypedPluginInterface.so", RTLD_LAZY);
00167 if(g_class_loader_library_handle)
00168 cout << "Shared object successfully loaded into memory." << endl;
00169 else
00170 {
00171 cout << "Error: Failed to load shared object into memory." << endl;
00172 exit(-1);
00173 }
00174 }
00175
00176 template <typename T> T getPluginFunction(const std::string& function_name)
00177
00178 {
00179 void* ptr = dlsym(g_class_loader_library_handle, function_name.c_str());
00180 return((T)(ptr));
00181 }
00182
00183 vector<string> getCLIArguments()
00184
00185 {
00186 return(g_cli_arguments);
00187 }
00188
00189 void generateFile(string filename, string contents)
00190
00191 {
00192 std::ofstream file;
00193 file.open(filename.c_str());
00194 file << contents;
00195 file.close();
00196 }
00197
00198 std::string getPluginlibSharedFolder()
00199
00200 {
00201 vector<std::string> allVals = parseToStringVector(callCommandLine("catkin_find pluginlib --share"));
00202 assert(allVals.size() > 0);
00203 return(allVals.at(0));
00204 }
00205
00206 string getTypedClassLoaderTemplate()
00207
00208 {
00209 std::ifstream file;
00210 string path = getPluginlibSharedFolder() + "/typed_class_loader_template.cpp";
00211 file.open(path.c_str());
00212 if(!file)
00213 {
00214 cout << "Error: Cannot find file " + path + " to generate class loader";
00215 exit(-1);
00216 }
00217
00218 string contents;
00219 while(!file.eof())
00220 {
00221 char c;
00222 file.get(c);
00223 contents.push_back(c);
00224 cout << c;
00225 }
00226
00227 return contents;
00228 }
00229
00230 string getTypedClassLoaderTemplateWithBaseSet()
00231
00232 {
00233 string class_template = getTypedClassLoaderTemplate();
00234 string class_with_type_set;
00235 for(unsigned int c = 0; c < class_template.size(); c++)
00236 {
00237 if(class_template.at(c) == '$')
00238 class_with_type_set += baseClass();
00239 else if(class_template.at(c) == '@')
00240 class_with_type_set += "#include \"" + baseClassHeader() + "\"";
00241 else
00242 class_with_type_set.push_back(class_template.at(c));
00243 }
00244 return(class_with_type_set);
00245 }
00246
00247 void handleFindPluginRequest()
00248
00249 {
00250
00251 typedef std::string (*WhereIsFunc)(const string&, const string&);
00252 WhereIsFunc f = getPluginFunction<WhereIsFunc>("whereIsPluginLocated");
00253
00254 cout << "Attempting to find plugin " << pluginName() << " exported from package " << packageName() << "..." << endl;
00255
00256 if(f)
00257 cout << "Plugin " << pluginName() << " is located in library " << f(packageName(), pluginName()) << endl;
00258 else
00259 {
00260 cout << "Error: Could not find function 'whereIsPluginLocated' in shared object." << endl;
00261 exit(-1);
00262 }
00263 }
00264
00265 void handleListPluginsRequest()
00266
00267 {
00268
00269 typedef std::vector<std::string> (*ListFunc)(const string&);
00270 ListFunc f = getPluginFunction<ListFunc>("availablePlugins");
00271
00272 cout << "The following plugins are available in package " << packageName() << ":" << endl;
00273 if(f)
00274 {
00275
00276 std::vector<std::string> plugins = f(packageName());
00277 for(unsigned int c = 0; c < plugins.size(); c++)
00278 cout << plugins.at(c) << endl;
00279 }
00280 else
00281 {
00282 cout << "Error: Could not find function 'availablePlugins' in shared object." << endl;
00283 exit(-1);
00284 }
00285 }
00286
00287 void handleLoadPluginRequest()
00288
00289 {
00290
00291 typedef bool (*LoadPluginFunc)(const string&, const string&);
00292 LoadPluginFunc f = getPluginFunction<LoadPluginFunc>("loadPlugin");
00293 string plugin_name = getCLIArguments().at(4);
00294 cout << "Attempting to find plugin " << plugin_name << "..." << endl;
00295 if(f)
00296 {
00297 if(f(packageName(), plugin_name))
00298 cout << "Opened plugin successfully :)" << endl;
00299 else
00300 {
00301 cout << "Error: Plugin did not open :(" << endl;
00302 exit(-1);
00303 }
00304 }
00305 else
00306 {
00307 cout << "Error: Could not find function 'loadPlugin' in shared object." << endl;
00308 exit(-1);
00309 }
00310 }
00311
00312 vector<string> parseToStringVector(std::string newline_delimited_str)
00313
00314 {
00315 string next;
00316 vector<string> parse_result;
00317 for(unsigned int c = 0; c < newline_delimited_str.size(); c++)
00318 {
00319 char ch = newline_delimited_str.at(c);
00320 if(ch == '\n')
00321 {
00322 parse_result.push_back(next);
00323 next = "";
00324 }
00325 else
00326 next.push_back(ch);
00327 }
00328 return(parse_result);
00329 }
00330
00331 void processUserCommand()
00332
00333 {
00334 string verb = commandVerb();
00335
00336 if (verb == "find")
00337 handleFindPluginRequest();
00338 else if (verb == "list")
00339 handleListPluginsRequest();
00340 else if(verb == "load")
00341 handleLoadPluginRequest();
00342 else
00343 cout << "Error: Unknown verb for plugin_tool, available verbs are 'load', 'list', and 'find'." << endl;
00344 }
00345
00346 void setCLIArguments(int argc, char* argv[])
00347
00348 {
00349 g_cli_arguments = vector<string>(argc);
00350 for(int c = 0; c < argc; c++)
00351 g_cli_arguments.at(c) = string(argv[c]);
00352 }
00353
00354 string stripNewlineCharacters(const std::string& s)
00355
00356 {
00357 string stripped;
00358 for(unsigned int c = 0; c < s.size(); c++)
00359 {
00360 if(s.at(c) != '\n')
00361 stripped.push_back(s.at(c));
00362 }
00363 return stripped;
00364 }
00365
00366 bool verifyCLIArguments()
00367
00368 {
00369 vector<string> args = getCLIArguments();
00370
00371 if(args.size() < 5)
00372 {
00373 cout << "Not enough arguments. Usage: plugin_tool <BASE CLASS> <BASE_CLASS_HEADER> <PACKAGE_NAME> <find [class_name] | list | load [class_name]>";
00374 return false;
00375 }
00376
00377 for(int c = 0; c < args.size(); c++)
00378 cout << "Arg " << c << ": " << args.at(c) << endl;
00379
00380 return(true);
00381 }