1

I'm writing a C++ program using the Boost libraries. I need to be able to find the full path of an executable, given only the name. This would be the equivalent of the Unix shell's which utility, Windows' where, or Python's shutil.which.

Is there a way of doing this? I could of course write my own, by iterating over the PATH environment variable, but for portability I'd need to consider things like splitting on : or ;, etc, and if there's a pre-written (and tested!) routine for this I'd prefer to use it.

Paul Moore
  • 6,569
  • 6
  • 40
  • 47

2 Answers2

0

There's nothing that directly implements this in boost. You could either:

  1. Read contents of PATH with getenv(), use Boost File System to deal with the paths in a portable manner, and handle the multi-path splitting manually - doesn't seem like the number of split characters could be insane, just a few alternatives
  2. invoke your shell's existing which program (or variant thereof)
  3. invoke a simple python program calling shutil.which, e.g. system("python -c \"import shutil; shutil.which('ls');\"")
Community
  • 1
  • 1
paul-g
  • 3,797
  • 2
  • 21
  • 36
  • OK, fair enough. It's a bit of a shame there's nothing available, but as you say it's not a disaster to write it myself. I don't want to start shelling out to other programs, as the reason I'm writing this application in C++ is performance and low footprint, and calling subprocesses would kill that (at that point I probably might as well write the whole thing in Python anyway...) – Paul Moore Aug 12 '16 at 10:41
  • Mhm, OK. From a performance POV it may be an overkill to write this type of thing in C++; and also a bit counter-productive; `python` has much better support for system level tasks IMHO. I don't know your context, but you could presumably just load all the path information at program startup, which would take very little time in any language – paul-g Aug 12 '16 at 10:44
0

"Write my own" is how this is typically done. While this might've been a bear in C, with C++ and its rich std::string class this becomes a no-brainer. Don't even need Boost. This would be a typical homework assignment in introductory C++ courses:

std::string s=getenv("PATH");

const char sep=':';  // Or use ';', if you feel like it.

auto b=s.begin(), e=s.end();

while (b != e)
{
    if (*b == sep)
    {
        ++b;
        continue;
    }

    auto p=b;
    b=std::find(b, e, sep);

    auto check=std::string(p, b) + "/" + filename;

    if (access(filename.c_str(), X_OK) == 0)
    {
          // Found it. Insert code here.
    }
}

This is such a non-issue, it would've probably been faster to just knock this out, then try to find some library function, somewhere, that does the same thing.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Sure, except this type of code is not exactly portable when working with filesystems: `auto check=std::string(p, b) + "/" + filename;` (i.e. the hardcoded `/`) and is the type of mistake you open yourself to when doing it yourself IMHO; the OP is not asking how to do it, but how to do it in a portable manner, which I think makes sense; – paul-g Aug 12 '16 at 10:52
  • Also, `std::string`, on Windows at least, doesn't support the full Unicode character set, which the filesystem does. So a portable version would need to do encoding conversions, or use wstring. Basically, it's simple enough in a "works for me" context, not so much for something that needs to work for a lot of users... – Paul Moore Aug 12 '16 at 12:58