From 3364a379e8d0c67e8e8bc5e8b6e3a8ad4b60fea2 Mon Sep 17 00:00:00 2001 From: Brian Gerkey Date: Sun, 23 Oct 2011 23:45:43 +0000 Subject: [PATCH] Down to 8 test failures. Almost there... --- tools/rospack/rp.cpp | 173 ++++++++++++- tools/rospack/rp.h | 16 +- tools/rospack/rp_main.cpp | 495 +++++++++++++++++++++++++++++++------- 3 files changed, 586 insertions(+), 98 deletions(-) diff --git a/tools/rospack/rp.cpp b/tools/rospack/rp.cpp index 1be204e1..b83edbe1 100644 --- a/tools/rospack/rp.cpp +++ b/tools/rospack/rp.cpp @@ -67,9 +67,11 @@ static const char* SRV_GEN_GENERATED_FILE = "generated"; static const char* MANIFEST_TAG_PACKAGE = "package"; static const char* MANIFEST_TAG_ROSDEP = "rosdep"; static const char* MANIFEST_TAG_VERSIONCONTROL = "versioncontrol"; +static const char* MANIFEST_TAG_EXPORT = "export"; static const char* MANIFEST_ATTR_NAME = "name"; static const char* MANIFEST_ATTR_TYPE = "type"; static const char* MANIFEST_ATTR_URL = "url"; +static const char* MANIFEST_PREFIX = "${prefix}"; static const int MAX_CRAWL_DEPTH = 1000; static const int MAX_DEPENDENCY_DEPTH = 1000; static const double DEFAULT_MAX_CACHE_AGE = 60.0; @@ -252,7 +254,7 @@ Rosstackage::deps(const std::string& name, bool direct, { computeDeps(stackage); std::vector deps_vec; - gatherDeps(stackage, direct, deps_vec); + gatherDeps(stackage, direct, POSTORDER, deps_vec); for(std::vector::const_iterator it = deps_vec.begin(); it != deps_vec.end(); ++it) @@ -280,7 +282,7 @@ Rosstackage::dependsOn(const std::string& name, bool direct, { computeDeps(it->second, true); std::vector deps_vec; - gatherDeps(it->second, direct, deps_vec); + gatherDeps(it->second, direct, POSTORDER, deps_vec); for(std::vector::const_iterator iit = deps_vec.begin(); iit != deps_vec.end(); ++iit) @@ -317,7 +319,7 @@ Rosstackage::depsIndent(const std::string& name, bool direct, std::vector deps_vec; std::tr1::unordered_set deps_hash; std::vector indented_deps; - gatherDepsFull(stackage, direct, 0, deps_hash, deps_vec, true, indented_deps); + gatherDepsFull(stackage, direct, POSTORDER, 0, deps_hash, deps_vec, true, indented_deps); for(std::vector::const_iterator it = indented_deps.begin(); it != indented_deps.end(); ++it) @@ -345,7 +347,7 @@ Rosstackage::depsManifests(const std::string& name, bool direct, { computeDeps(stackage); std::vector deps_vec; - gatherDeps(stackage, direct, deps_vec); + gatherDeps(stackage, direct, POSTORDER, deps_vec); for(std::vector::const_iterator it = deps_vec.begin(); it != deps_vec.end(); ++it) @@ -376,7 +378,7 @@ Rosstackage::rosdeps(const std::string& name, bool direct, // rosdeps include the current package deps_vec.push_back(stackage); if(!direct) - gatherDeps(stackage, direct, deps_vec); + gatherDeps(stackage, direct, POSTORDER, deps_vec); for(std::vector::const_iterator it = deps_vec.begin(); it != deps_vec.end(); ++it) @@ -419,7 +421,7 @@ Rosstackage::vcs(const std::string& name, bool direct, // vcs include the current package deps_vec.push_back(stackage); if(!direct) - gatherDeps(stackage, direct, deps_vec); + gatherDeps(stackage, direct, POSTORDER, deps_vec); for(std::vector::const_iterator it = deps_vec.begin(); it != deps_vec.end(); ++it) @@ -453,6 +455,72 @@ Rosstackage::vcs(const std::string& name, bool direct, return true; } +bool +Rosstackage::exports(const std::string& name, const std::string& lang, + const std::string& attrib, bool deps_only, + std::vector& flags) +{ + if(!stackages_.count(name)) + { + log_error("librospack", std::string("no such package ") + name); + return false; + } + Stackage* stackage = stackages_[name]; + try + { + computeDeps(stackage); + std::vector deps_vec; + if(!deps_only) + deps_vec.push_back(stackage); + gatherDeps(stackage, false, PREORDER, deps_vec); + for(std::vector::const_iterator it = deps_vec.begin(); + it != deps_vec.end(); + ++it) + { + rospack_tinyxml::TiXmlElement* root = get_manifest_root(*it); + for(rospack_tinyxml::TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT); + ele; + ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT)) + { + for(rospack_tinyxml::TiXmlElement* ele2 = ele->FirstChildElement(lang); + ele2; + ele2 = ele2->NextSiblingElement(lang)) + { + const char *att_str; + if((att_str = ele2->Attribute(attrib.c_str()))) + { + std::string expanded_str; + if(!expandExportString(*it, att_str, expanded_str)) + return false; + flags.push_back(expanded_str); + } + } + } + + // We automatically point to msg_gen and msg_srv directories if + // certain files are present + fs::path msg_gen = fs::path((*it)->path_) / MSG_GEN_GENERATED_DIR; + fs::path srv_gen = fs::path((*it)->path_) / SRV_GEN_GENERATED_DIR; + if(fs::is_regular_file(msg_gen / MSG_GEN_GENERATED_FILE)) + { + msg_gen /= fs::path("cpp") / "include"; + flags.push_back(std::string("-I" + msg_gen.string())); + } + if(fs::is_regular_file(srv_gen / SRV_GEN_GENERATED_FILE)) + { + srv_gen /= fs::path("cpp") / "include"; + flags.push_back(std::string("-I" + srv_gen.string())); + } + } + } + catch(Exception& e) + { + log_error("librospack", e.what()); + return false; + } + return true; +} + bool Rosstackage::depsMsgSrv(const std::string& name, bool direct, std::vector& gens) @@ -467,7 +535,7 @@ Rosstackage::depsMsgSrv(const std::string& name, bool direct, { computeDeps(stackage); std::vector deps_vec; - gatherDeps(stackage, direct, deps_vec); + gatherDeps(stackage, direct, POSTORDER, deps_vec); for(std::vector::const_iterator it = deps_vec.begin(); it != deps_vec.end(); ++it) @@ -665,16 +733,19 @@ Rosstackage::computeDeps(Stackage* stackage, bool ignore_errors) void Rosstackage::gatherDeps(Stackage* stackage, bool direct, + traversal_order_t order, std::vector& deps) { std::tr1::unordered_set deps_hash; std::vector indented_deps; - gatherDepsFull(stackage, direct, 0, deps_hash, deps, false, indented_deps); + gatherDepsFull(stackage, direct, order, 0, + deps_hash, deps, false, indented_deps); } // Pre-condition: computeDeps(stackage) succeeded void -Rosstackage::gatherDepsFull(Stackage* stackage, bool direct, int depth, +Rosstackage::gatherDepsFull(Stackage* stackage, bool direct, + traversal_order_t order, int depth, std::tr1::unordered_set& deps_hash, std::vector& deps, bool get_indented_deps, @@ -700,12 +771,14 @@ Rosstackage::gatherDepsFull(Stackage* stackage, bool direct, int depth, } deps_hash.insert(*it); - if(!direct) - gatherDepsFull(*it, direct, depth+1, deps_hash, deps, - get_indented_deps, indented_deps); // We maintain the vector because the original rospack guaranteed // ordering in dep reporting. - if(first) + if(first && order == PREORDER) + deps.push_back(*it); + if(!direct) + gatherDepsFull(*it, direct, order, depth+1, deps_hash, deps, + get_indented_deps, indented_deps); + if(first && order == POSTORDER) deps.push_back(*it); } } @@ -948,6 +1021,80 @@ Rosstackage::validateCache() return ros_root_ok && ros_package_path_ok; } +bool +Rosstackage::expandExportString(Stackage* stackage, + const std::string& instring, + std::string& outstring) +{ + outstring = instring; + for(std::string::size_type i = outstring.find(MANIFEST_PREFIX); + i != std::string::npos; + i = outstring.find(MANIFEST_PREFIX)) + { + outstring.replace(i, std::string(MANIFEST_PREFIX).length(), + stackage->path_); + } + + // Do backquote substitution. E.g., if we find this string: + // `pkg-config --cflags gdk-pixbuf-2.0` + // We replace it with the result of executing the command + // contained within the backquotes (reading from its stdout), which + // might be something like: + // -I/usr/include/gtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include + + // Construct and execute the string + // We do the assignment first to ensure that if backquote expansion (or + // anything else) fails, we'll get a non-zero exit status from pclose(). + std::string cmd = std::string("ret=\"") + outstring + "\" && echo $ret"; + + // Remove embedded newlines + std::string token("\n"); + for (std::string::size_type s = cmd.find(token); + s != std::string::npos; + s = cmd.find(token, s)) + cmd.replace(s,token.length(),std::string(" ")); + + FILE* p; + if(!(p = popen(cmd.c_str(), "r"))) + { + std::string errmsg = + std::string("failed to execute backquote expression ") + + cmd + " in " + + stackage->manifest_path_; + log_warn("librospack", errmsg, true); + return false; + } + else + { + char buf[8192]; + memset(buf,0,sizeof(buf)); + // Read the command's output + do + { + clearerr(p); + while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p)); + } while(ferror(p) && errno == EINTR); + // Close the subprocess, checking exit status + if(pclose(p) != 0) + { + std::string errmsg = + std::string("got non-zero exit status from executing backquote expression ") + + cmd + " in " + + stackage->manifest_path_; + return false; + } + else + { + // Strip trailing newline, which was added by our call to echo + buf[strlen(buf)-1] = '\0'; + // Replace the backquote expression with the new text + outstring = buf; + } + } + + return true; +} + ///////////////////////////////////////////////////////////// // Rospack methods ///////////////////////////////////////////////////////////// diff --git a/tools/rospack/rp.h b/tools/rospack/rp.h index 903d33f9..dcb9b793 100644 --- a/tools/rospack/rp.h +++ b/tools/rospack/rp.h @@ -45,6 +45,12 @@ typedef enum CRAWL_DOWN } crawl_direction_t; +typedef enum +{ + POSTORDER, + PREORDER +} traversal_order_t; + class Stackage; class Rosstackage @@ -64,8 +70,10 @@ class Rosstackage void loadManifest(Stackage* stackage); void computeDeps(Stackage* stackage, bool ignore_errors=false); void gatherDeps(Stackage* stackage, bool direct, + traversal_order_t order, std::vector& deps); - void gatherDepsFull(Stackage* stackage, bool direct, int depth, + void gatherDepsFull(Stackage* stackage, bool direct, + traversal_order_t order, int depth, std::tr1::unordered_set& deps_hash, std::vector& deps, bool get_indented_deps, @@ -74,6 +82,9 @@ class Rosstackage bool readCache(); void writeCache(); bool validateCache(); + bool expandExportString(Stackage* stackage, + const std::string& instring, + std::string& outstring); protected: std::tr1::unordered_map stackages_; @@ -103,6 +114,9 @@ class Rosstackage std::vector& rosdeps); bool vcs(const std::string& name, bool direct, std::vector& vcs); + bool exports(const std::string& name, const std::string& lang, + const std::string& attrib, bool deps_only, + std::vector& flags); void debug_dump(); }; diff --git a/tools/rospack/rp_main.cpp b/tools/rospack/rp_main.cpp index c2b7b4a7..9820bd5e 100644 --- a/tools/rospack/rp_main.cpp +++ b/tools/rospack/rp_main.cpp @@ -27,6 +27,8 @@ #include "rp.h" #include +#include +#include #include #include #include @@ -35,6 +37,14 @@ namespace po = boost::program_options; const char* usage(); bool parse_args(int argc, char** argv, po::variables_map& vm); +void parse_compiler_flags(const std::string& instring, + const std::string& token, + bool select, + bool last, + std::string& outstring); +void deduplicate_tokens(const std::string& instring, + bool last, + std::string& outstring); int main(int argc, char** argv) @@ -50,6 +60,14 @@ main(int argc, char** argv) std::string command; std::string package; bool package_given = false; + bool deps_only = false; + std::string lang; + std::string attrib; + std::string top; + std::string target; + bool zombie_only = false; + std::string length_str; + int length; if(vm.count("command")) command = vm["command"].as(); if(!command.size()) @@ -73,19 +91,45 @@ main(int argc, char** argv) // try to determine package from directory context rp.inPackage(package); } + if(vm.count("deps-only")) + deps_only = true; + if(vm.count("lang")) + lang = vm["lang"].as(); + if(vm.count("attrib")) + attrib = vm["attrib"].as(); + if(vm.count("top")) + top = vm["top"].as(); + if(vm.count("target")) + target = vm["target"].as(); + if(vm.count("zombie-only")) + zombie_only = true; + if(vm.count("length")) + { + length_str = vm["length"].as(); + length = atoi(length_str.c_str()); + } + else + { + if(zombie_only) + length = -1; + else + length = 20; + } - + // COMMAND: profile if(command == "profile") { - if(package_given) + if(package_given || target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } rospack::log_error("rospack", "profile output not yet implemented"); // TODO return 0; } + // COMMAND: find [package] else if(command == "find") { if(!package.size()) @@ -93,20 +137,25 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::string path; if(!rp.find(package, path)) return 1; - else - { - printf("%s\n", path.c_str()); - return 0; - } + printf("%s\n", path.c_str()); + return 0; } + // COMMAND: list else if(command == "list") { - if(package_given) + if(package_given || target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } std::vector > list; @@ -119,11 +168,13 @@ main(int argc, char** argv) } return 0; } + // COMMAND: list-names else if(command == "list-names") { - if(package_given) + if(package_given || target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } std::vector > list; @@ -136,11 +187,13 @@ main(int argc, char** argv) } return 0; } + // COMMAND: list-duplicates else if(command == "list-duplicates") { - if(package_given) + if(package_given || target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } std::vector dups; @@ -148,29 +201,29 @@ main(int argc, char** argv) // list-duplicates returns 0 if no duplicates if(!dups.size()) return 0; - else + // if there are dups, list-duplicates prints them and returns non-zero + for(std::vector::const_iterator it = dups.begin(); + it != dups.end(); + ++it) { - // if there are dups, list-duplicates prints them and returns non-zero - for(std::vector::const_iterator it = dups.begin(); - it != dups.end(); - ++it) - { - printf("%s\n", (*it).c_str()); - } - return 1; + printf("%s\n", (*it).c_str()); } + return 1; } + // COMMAND: langs else if(command == "langs") { - if(package_given) + if(package_given || target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } rospack::log_error("rospack", std::string("command ") + command + " not implemented"); return 1; } + // COMMAND: depends [package] (alias: deps) else if(command == "depends" || command == "deps" || command == "depends1" || command == "deps1") { @@ -179,18 +232,22 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector deps; if(!rp.deps(package, (command == "depends1" || command == "deps1"), deps)) return 1; - else - { - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } + for(std::vector::const_iterator it = deps.begin(); + it != deps.end(); + ++it) + printf("%s\n", it->c_str()); + return 0; } + // COMMAND: depends-manifests [package] (alias: deps-manifests) else if(command == "depends-manifests" || command == "deps-manifests") { if(!package.size()) @@ -198,19 +255,23 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector manifests; if(!rp.depsManifests(package, false, manifests)) return 1; - else - { - for(std::vector::const_iterator it = manifests.begin(); - it != manifests.end(); - ++it) + for(std::vector::const_iterator it = manifests.begin(); + it != manifests.end(); + ++it) printf("%s ", it->c_str()); - printf("\n"); - return 0; - } + printf("\n"); + return 0; } + // COMMAND: depends-msgsrv [package] (alias: deps-msgsrv) else if(command == "depends-msgsrv" || command == "deps-msgsrv") { if(!package.size()) @@ -218,19 +279,23 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector gens; if(!rp.depsMsgSrv(package, false, gens)) return 1; - else - { - for(std::vector::const_iterator it = gens.begin(); - it != gens.end(); - ++it) - printf("%s ", it->c_str()); - printf("\n"); - return 0; - } + for(std::vector::const_iterator it = gens.begin(); + it != gens.end(); + ++it) + printf("%s ", it->c_str()); + printf("\n"); + return 0; } + // COMMAND: depends-indent [package] (alias: deps-indent) else if(command == "depends-indent" || command == "deps-indent") { if(!package.size()) @@ -238,18 +303,23 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector deps; if(!rp.depsIndent(package, false, deps)) return 1; - else - { - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } + for(std::vector::const_iterator it = deps.begin(); + it != deps.end(); + ++it) + printf("%s\n", it->c_str()); + return 0; } + // COMMAND: rosdep [package] (alias: rosdeps) + // COMMAND: rosdep0 [package] (alias: rosdeps0) else if(command == "rosdep" || command == "rosdeps" || command == "rosdep0" || command == "rosdeps0") { @@ -258,18 +328,23 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector rosdeps; if(!rp.rosdeps(package, (command == "rosdep0" || command == "rosdeps0"), rosdeps)) return 1; - else - { - for(std::vector::const_iterator it = rosdeps.begin(); - it != rosdeps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } + for(std::vector::const_iterator it = rosdeps.begin(); + it != rosdeps.end(); + ++it) + printf("%s\n", it->c_str()); + return 0; } + // COMMAND: vcs [package] + // COMMAND: vcs0 [package] else if(command == "vcs" || command == "vcs0") { if(!package.size()) @@ -277,18 +352,23 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector vcs; if(!rp.vcs(package, (command == "vcs0"), vcs)) return 1; - else - { - for(std::vector::const_iterator it = vcs.begin(); - it != vcs.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } + for(std::vector::const_iterator it = vcs.begin(); + it != vcs.end(); + ++it) + printf("%s\n", it->c_str()); + return 0; } + // COMMAND: depends-on [package] + // COMMAND: depends-on1 [package] else if(command == "depends-on" || command == "depends-on1") { if(!package.size()) @@ -296,23 +376,190 @@ main(int argc, char** argv) rospack::log_error("rospack", "no package given"); return 1; } + if(target.size() || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } std::vector deps; if(!rp.dependsOn(package, (command == "depends-on1"), deps)) return 1; - else - { - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } + for(std::vector::const_iterator it = deps.begin(); + it != deps.end(); + ++it) + printf("%s\n", it->c_str()); + return 0; } + // COMMAND: export [--deps-only] --lang= --attrib= [package] + else if(command == "export") + { + if(!package.size() || !lang.size() || !attrib.size()) + { + rospack::log_error("rospack", "no package / lang / attrib given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, lang, attrib, deps_only, flags)) + return 1; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + printf("%s ", it->c_str()); + printf("\n"); + return 0; + } + // COMMAND: plugins --attrib= [--top=] [package] + else if(command == "plugins") + { + rospack::log_error("rospack", + std::string("command ") + command + " not implemented"); + return 1; + } + // COMMAND: cflags-only-I [--deps-only] [package] + else if(command == "cflags-only-I") + { + if(!package.size()) + { + rospack::log_error("rospack", "no package given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, "cpp", "cflags", deps_only, flags)) + return 1; + std::string combined; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + combined.append(*it + " "); + std::string result; + parse_compiler_flags(combined, "-I", true, false, result); + printf("%s\n", result.c_str()); + return 0; + } + // COMMAND: cflags-only-other [--deps-only] [package] + else if(command == "cflags-only-other") + { + if(!package.size()) + { + rospack::log_error("rospack", "no package given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, "cpp", "cflags", deps_only, flags)) + return 1; + std::string combined; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + combined.append(*it + " "); + std::string result; + parse_compiler_flags(combined, "-I", false, false, result); + printf("%s\n", result.c_str()); + return 0; + } + // COMMAND: libs-only-L [--deps-only] [package] + else if(command == "libs-only-L") + { + if(!package.size()) + { + rospack::log_error("rospack", "no package given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) + return 1; + std::string combined; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + combined.append(*it + " "); + std::string result; + parse_compiler_flags(combined, "-L", true, false, result); + printf("%s\n", result.c_str()); + return 0; + } + // COMMAND: libs-only-l [--deps-only] [package] + else if(command == "libs-only-l") + { + if(!package.size()) + { + rospack::log_error("rospack", "no package given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) + return 1; + std::string combined; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + combined.append(*it + " "); + std::string result; + parse_compiler_flags(combined, "-l", true, true, result); + printf("%s\n", result.c_str()); + return 0; + } + // COMMAND: libs-only-other [--deps-only] [package] + else if(command == "libs-only-other") + { + if(!package.size()) + { + rospack::log_error("rospack", "no package given"); + return 1; + } + if(target.size() || top.size() || length_str.size() || zombie_only) + { + rospack::log_error("rospack", "invalid option(s) given"); + return 1; + } + std::vector flags; + if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) + return 1; + std::string combined; + for(std::vector::const_iterator it = flags.begin(); + it != flags.end(); + ++it) + combined.append(*it + " "); + std::string intermediate; + parse_compiler_flags(combined, "-L", false, false, intermediate); + std::string result; + parse_compiler_flags(intermediate, "-l", false, false, result); + printf("%s\n", result.c_str()); + return 0; + } + // COMMAND: help else if(command == "help") { - if(package_given) + if(package_given || top.size() || length_str.size() || + zombie_only || deps_only || lang.size() || attrib.size()) { - rospack::log_error("rospack", "no package allowed"); + rospack::log_error("rospack", "invalid option(s) given"); return 1; } printf("%s", usage()); @@ -326,6 +573,86 @@ main(int argc, char** argv) } } +void +deduplicate_tokens(const std::string& instring, + bool last, + std::string& outstring) +{ + std::vector vec; + std::tr1::unordered_set set; + boost::split(vec, instring, + boost::is_any_of("\t "), + boost::token_compress_on); + if(last) + std::reverse(vec.begin(), vec.end()); + std::vector vec_out; + vec_out.resize(vec.size()); + int i = 0; + for(std::vector::const_iterator it = vec.begin(); + it != vec.end(); + ++it) + { + if(set.find(*it) == set.end()) + { + vec_out[i] = *it; + set.insert(*it); + i++; + } + } + if(last) + std::reverse(vec_out.begin(), vec_out.end()); + for(std::vector::const_iterator it = vec_out.begin(); + it != vec_out.end(); + ++it) + outstring.append(*it + " "); +} + +void +parse_compiler_flags(const std::string& instring, + const std::string& token, + bool select, + bool last, + std::string& outstring) +{ + std::string intermediate; + std::vector result_vec; + boost::split(result_vec, instring, + boost::is_any_of("\t "), + boost::token_compress_on); + for(std::vector::const_iterator it = result_vec.begin(); + it != result_vec.end(); + ++it) + { + // Combined into one arg + if(it->size() > token.size() && it->substr(0,token.size()) == token) + { + if(select) + intermediate.append(it->substr(token.size()) + " "); + } + // Space-separated + else if((*it) == token) + { + std::vector::const_iterator iit = it; + if(++iit != result_vec.end()) + { + if(it->size() >= token.size() && it->substr(0,token.size()) == token) + { + // skip it + } + else + { + if(select) + intermediate.append((*iit) + " "); + it = iit; + } + } + } + else if(!select) + intermediate.append((*it) + " "); + } + deduplicate_tokens(intermediate, last, outstring); +} + const char* usage() { return "USAGE: rospack [options] [package]\n"